diff --git a/.gitignore b/.gitignore index 16a95637..356ce0f8 100644 --- a/.gitignore +++ b/.gitignore @@ -79,12 +79,12 @@ web-build/ # Turborepo .turbo/ -# generated by bob -lib/ +# # generated by bob +# lib/ -# React Native Codegen -ios/generated -android/generated +# # React Native Codegen +# ios/generated +# android/generated # React Native Nitro Modules nitrogen/ diff --git a/.node-version b/.node-version new file mode 100644 index 00000000..a1954016 --- /dev/null +++ b/.node-version @@ -0,0 +1 @@ +24.0.2 diff --git a/ReactNativeEnrichedMarkdown.podspec b/ReactNativeEnrichedMarkdown.podspec index e191da8a..2a022817 100644 --- a/ReactNativeEnrichedMarkdown.podspec +++ b/ReactNativeEnrichedMarkdown.podspec @@ -25,8 +25,21 @@ Pod::Spec.new do |s| s.dependency 'iosMath', '~> 0.9' end + # Quoted imports like #import "Foo.h" do not search subdirs recursively; list every + # ios folder that contains headers so renderer/ utils/ attachments/ etc. cross-imports resolve. + ios_header_paths = %w[ + ios ios/attachments ios/input ios/input/internals ios/input/styles ios/internals ios/parser + ios/renderer ios/styles ios/utils ios/views + ].map { |p| "\"$(PODS_TARGET_SRCROOT)/#{p}\"" }.join(' ') + # Vendored Fabric codegen (see package.json codegenConfig.includesGeneratedCode). Resolves + # e.g. when the app does not re-run RN codegen + # for this library. + generated_codegen_path = '"$(PODS_TARGET_SRCROOT)/ios/generated/ReactCodegen"' + s.pod_target_xcconfig = { - 'HEADER_SEARCH_PATHS' => '"$(PODS_TARGET_SRCROOT)/cpp/md4c" "$(PODS_TARGET_SRCROOT)/cpp/parser" "$(PODS_TARGET_SRCROOT)/ios/internals" "$(PODS_TARGET_SRCROOT)/ios/input/internals"', + 'HEADER_SEARCH_PATHS' => "\"$(PODS_TARGET_SRCROOT)/cpp/md4c\" \"$(PODS_TARGET_SRCROOT)/cpp/parser\" #{ios_header_paths} #{generated_codegen_path}", + # React / SwiftUI modules use framework-style modules; our ObjC uses plain quoted includes. + 'CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES' => 'YES', 'GCC_PREPROCESSOR_DEFINITIONS' => preprocessor_defs, 'CLANG_CXX_LANGUAGE_STANDARD' => 'c++17' } diff --git a/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownManagerDelegate.java b/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownManagerDelegate.java new file mode 100644 index 00000000..86b5312d --- /dev/null +++ b/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownManagerDelegate.java @@ -0,0 +1,72 @@ +/** +* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). +* +* Do not edit this file as changes may cause incorrect behavior and will be lost +* once the code is regenerated. +* +* @generated by codegen project: GeneratePropsJavaDelegate.js +*/ + +package com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import com.facebook.react.bridge.ColorPropConverter; +import com.facebook.react.bridge.ReadableArray; +import com.facebook.react.bridge.ReadableMap; +import com.facebook.react.uimanager.BaseViewManager; +import com.facebook.react.uimanager.BaseViewManagerDelegate; +import com.facebook.react.uimanager.LayoutShadowNode; + +@SuppressWarnings("deprecation") +public class EnrichedMarkdownManagerDelegate & EnrichedMarkdownManagerInterface> extends BaseViewManagerDelegate { + public EnrichedMarkdownManagerDelegate(U viewManager) { + super(viewManager); + } + @Override + public void setProperty(T view, String propName, @Nullable Object value) { + switch (propName) { + case "markdown": + mViewManager.setMarkdown(view, value == null ? null : (String) value); + break; + case "markdownStyle": + mViewManager.setMarkdownStyle(view, (ReadableMap) value); + break; + case "enableLinkPreview": + mViewManager.setEnableLinkPreview(view, value == null ? true : (boolean) value); + break; + case "selectable": + mViewManager.setSelectable(view, value == null ? false : (boolean) value); + break; + case "selectionColor": + mViewManager.setSelectionColor(view, ColorPropConverter.getColor(value, view.getContext())); + break; + case "selectionHandleColor": + mViewManager.setSelectionHandleColor(view, ColorPropConverter.getColor(value, view.getContext())); + break; + case "md4cFlags": + mViewManager.setMd4cFlags(view, (ReadableMap) value); + break; + case "allowFontScaling": + mViewManager.setAllowFontScaling(view, value == null ? true : (boolean) value); + break; + case "maxFontSizeMultiplier": + mViewManager.setMaxFontSizeMultiplier(view, value == null ? 0f : ((Double) value).floatValue()); + break; + case "allowTrailingMargin": + mViewManager.setAllowTrailingMargin(view, value == null ? false : (boolean) value); + break; + case "streamingAnimation": + mViewManager.setStreamingAnimation(view, value == null ? false : (boolean) value); + break; + case "spoilerOverlay": + mViewManager.setSpoilerOverlay(view, value == null ? "particles" : (String) value); + break; + case "contextMenuItems": + mViewManager.setContextMenuItems(view, (ReadableArray) value); + break; + default: + super.setProperty(view, propName, value); + } + } +} diff --git a/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownManagerInterface.java b/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownManagerInterface.java new file mode 100644 index 00000000..435b5662 --- /dev/null +++ b/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownManagerInterface.java @@ -0,0 +1,32 @@ +/** +* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). +* +* Do not edit this file as changes may cause incorrect behavior and will be lost +* once the code is regenerated. +* +* @generated by codegen project: GeneratePropsJavaInterface.js +*/ + +package com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import com.facebook.react.bridge.ReadableArray; +import com.facebook.react.bridge.ReadableMap; +import com.facebook.react.uimanager.ViewManagerWithGeneratedInterface; + +public interface EnrichedMarkdownManagerInterface extends ViewManagerWithGeneratedInterface { + void setMarkdown(T view, @Nullable String value); + void setMarkdownStyle(T view, @Nullable ReadableMap value); + void setEnableLinkPreview(T view, boolean value); + void setSelectable(T view, boolean value); + void setSelectionColor(T view, @Nullable Integer value); + void setSelectionHandleColor(T view, @Nullable Integer value); + void setMd4cFlags(T view, @Nullable ReadableMap value); + void setAllowFontScaling(T view, boolean value); + void setMaxFontSizeMultiplier(T view, float value); + void setAllowTrailingMargin(T view, boolean value); + void setStreamingAnimation(T view, boolean value); + void setSpoilerOverlay(T view, @Nullable String value); + void setContextMenuItems(T view, @Nullable ReadableArray value); +} diff --git a/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownTextInputManagerDelegate.java b/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownTextInputManagerDelegate.java new file mode 100644 index 00000000..14583e63 --- /dev/null +++ b/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownTextInputManagerDelegate.java @@ -0,0 +1,138 @@ +/** +* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). +* +* Do not edit this file as changes may cause incorrect behavior and will be lost +* once the code is regenerated. +* +* @generated by codegen project: GeneratePropsJavaDelegate.js +*/ + +package com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import com.facebook.react.bridge.ColorPropConverter; +import com.facebook.react.bridge.ReadableArray; +import com.facebook.react.bridge.ReadableMap; +import com.facebook.react.uimanager.BaseViewManager; +import com.facebook.react.uimanager.BaseViewManagerDelegate; +import com.facebook.react.uimanager.LayoutShadowNode; + +@SuppressWarnings("deprecation") +public class EnrichedMarkdownTextInputManagerDelegate & EnrichedMarkdownTextInputManagerInterface> extends BaseViewManagerDelegate { + public EnrichedMarkdownTextInputManagerDelegate(U viewManager) { + super(viewManager); + } + @Override + public void setProperty(T view, String propName, @Nullable Object value) { + switch (propName) { + case "defaultValue": + mViewManager.setDefaultValue(view, value == null ? null : (String) value); + break; + case "placeholder": + mViewManager.setPlaceholder(view, value == null ? null : (String) value); + break; + case "placeholderTextColor": + mViewManager.setPlaceholderTextColor(view, ColorPropConverter.getColor(value, view.getContext())); + break; + case "editable": + mViewManager.setEditable(view, value == null ? false : (boolean) value); + break; + case "autoFocus": + mViewManager.setAutoFocus(view, value == null ? false : (boolean) value); + break; + case "scrollEnabled": + mViewManager.setScrollEnabled(view, value == null ? false : (boolean) value); + break; + case "autoCapitalize": + mViewManager.setAutoCapitalize(view, value == null ? null : (String) value); + break; + case "multiline": + mViewManager.setMultiline(view, value == null ? false : (boolean) value); + break; + case "cursorColor": + mViewManager.setCursorColor(view, ColorPropConverter.getColor(value, view.getContext())); + break; + case "selectionColor": + mViewManager.setSelectionColor(view, ColorPropConverter.getColor(value, view.getContext())); + break; + case "markdownStyle": + mViewManager.setMarkdownStyle(view, (ReadableMap) value); + break; + case "color": + mViewManager.setColor(view, ColorPropConverter.getColor(value, view.getContext())); + break; + case "fontSize": + mViewManager.setFontSize(view, value == null ? 0f : ((Double) value).floatValue()); + break; + case "lineHeight": + mViewManager.setLineHeight(view, value == null ? 0f : ((Double) value).floatValue()); + break; + case "fontFamily": + mViewManager.setFontFamily(view, value == null ? null : (String) value); + break; + case "fontWeight": + mViewManager.setFontWeight(view, value == null ? null : (String) value); + break; + case "isOnChangeMarkdownSet": + mViewManager.setIsOnChangeMarkdownSet(view, value == null ? false : (boolean) value); + break; + case "contextMenuItems": + mViewManager.setContextMenuItems(view, (ReadableArray) value); + break; + case "linkRegex": + mViewManager.setLinkRegex(view, (ReadableMap) value); + break; + default: + super.setProperty(view, propName, value); + } + } + + @Override + public void receiveCommand(T view, String commandName, ReadableArray args) { + switch (commandName) { + case "focus": + mViewManager.focus(view); + break; + case "blur": + mViewManager.blur(view); + break; + case "setValue": + mViewManager.setValue(view, args.getString(0)); + break; + case "setSelection": + mViewManager.setSelection(view, args.getInt(0), args.getInt(1)); + break; + case "toggleBold": + mViewManager.toggleBold(view); + break; + case "toggleItalic": + mViewManager.toggleItalic(view); + break; + case "toggleUnderline": + mViewManager.toggleUnderline(view); + break; + case "toggleStrikethrough": + mViewManager.toggleStrikethrough(view); + break; + case "toggleSpoiler": + mViewManager.toggleSpoiler(view); + break; + case "setLink": + mViewManager.setLink(view, args.getString(0)); + break; + case "insertLink": + mViewManager.insertLink(view, args.getString(0), args.getString(1)); + break; + case "removeLink": + mViewManager.removeLink(view); + break; + case "requestMarkdown": + mViewManager.requestMarkdown(view, args.getInt(0)); + break; + case "requestCaretRect": + mViewManager.requestCaretRect(view, args.getInt(0)); + break; + } + } +} diff --git a/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownTextInputManagerInterface.java b/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownTextInputManagerInterface.java new file mode 100644 index 00000000..5d981323 --- /dev/null +++ b/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownTextInputManagerInterface.java @@ -0,0 +1,52 @@ +/** +* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). +* +* Do not edit this file as changes may cause incorrect behavior and will be lost +* once the code is regenerated. +* +* @generated by codegen project: GeneratePropsJavaInterface.js +*/ + +package com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import com.facebook.react.bridge.ReadableArray; +import com.facebook.react.bridge.ReadableMap; +import com.facebook.react.uimanager.ViewManagerWithGeneratedInterface; + +public interface EnrichedMarkdownTextInputManagerInterface extends ViewManagerWithGeneratedInterface { + void setDefaultValue(T view, @Nullable String value); + void setPlaceholder(T view, @Nullable String value); + void setPlaceholderTextColor(T view, @Nullable Integer value); + void setEditable(T view, boolean value); + void setAutoFocus(T view, boolean value); + void setScrollEnabled(T view, boolean value); + void setAutoCapitalize(T view, @Nullable String value); + void setMultiline(T view, boolean value); + void setCursorColor(T view, @Nullable Integer value); + void setSelectionColor(T view, @Nullable Integer value); + void setMarkdownStyle(T view, @Nullable ReadableMap value); + void setColor(T view, @Nullable Integer value); + void setFontSize(T view, float value); + void setLineHeight(T view, float value); + void setFontFamily(T view, @Nullable String value); + void setFontWeight(T view, @Nullable String value); + void setIsOnChangeMarkdownSet(T view, boolean value); + void setContextMenuItems(T view, @Nullable ReadableArray value); + void setLinkRegex(T view, @Nullable ReadableMap value); + void focus(T view); + void blur(T view); + void setValue(T view, String markdown); + void setSelection(T view, int start, int end); + void toggleBold(T view); + void toggleItalic(T view); + void toggleUnderline(T view); + void toggleStrikethrough(T view); + void toggleSpoiler(T view); + void setLink(T view, String url); + void insertLink(T view, String text, String url); + void removeLink(T view); + void requestMarkdown(T view, int requestId); + void requestCaretRect(T view, int requestId); +} diff --git a/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownTextManagerDelegate.java b/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownTextManagerDelegate.java new file mode 100644 index 00000000..3fbf5476 --- /dev/null +++ b/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownTextManagerDelegate.java @@ -0,0 +1,72 @@ +/** +* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). +* +* Do not edit this file as changes may cause incorrect behavior and will be lost +* once the code is regenerated. +* +* @generated by codegen project: GeneratePropsJavaDelegate.js +*/ + +package com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import com.facebook.react.bridge.ColorPropConverter; +import com.facebook.react.bridge.ReadableArray; +import com.facebook.react.bridge.ReadableMap; +import com.facebook.react.uimanager.BaseViewManager; +import com.facebook.react.uimanager.BaseViewManagerDelegate; +import com.facebook.react.uimanager.LayoutShadowNode; + +@SuppressWarnings("deprecation") +public class EnrichedMarkdownTextManagerDelegate & EnrichedMarkdownTextManagerInterface> extends BaseViewManagerDelegate { + public EnrichedMarkdownTextManagerDelegate(U viewManager) { + super(viewManager); + } + @Override + public void setProperty(T view, String propName, @Nullable Object value) { + switch (propName) { + case "markdown": + mViewManager.setMarkdown(view, value == null ? null : (String) value); + break; + case "markdownStyle": + mViewManager.setMarkdownStyle(view, (ReadableMap) value); + break; + case "enableLinkPreview": + mViewManager.setEnableLinkPreview(view, value == null ? true : (boolean) value); + break; + case "selectable": + mViewManager.setSelectable(view, value == null ? false : (boolean) value); + break; + case "selectionColor": + mViewManager.setSelectionColor(view, ColorPropConverter.getColor(value, view.getContext())); + break; + case "selectionHandleColor": + mViewManager.setSelectionHandleColor(view, ColorPropConverter.getColor(value, view.getContext())); + break; + case "md4cFlags": + mViewManager.setMd4cFlags(view, (ReadableMap) value); + break; + case "allowFontScaling": + mViewManager.setAllowFontScaling(view, value == null ? true : (boolean) value); + break; + case "maxFontSizeMultiplier": + mViewManager.setMaxFontSizeMultiplier(view, value == null ? 0f : ((Double) value).floatValue()); + break; + case "allowTrailingMargin": + mViewManager.setAllowTrailingMargin(view, value == null ? false : (boolean) value); + break; + case "streamingAnimation": + mViewManager.setStreamingAnimation(view, value == null ? false : (boolean) value); + break; + case "spoilerOverlay": + mViewManager.setSpoilerOverlay(view, value == null ? "particles" : (String) value); + break; + case "contextMenuItems": + mViewManager.setContextMenuItems(view, (ReadableArray) value); + break; + default: + super.setProperty(view, propName, value); + } + } +} diff --git a/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownTextManagerInterface.java b/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownTextManagerInterface.java new file mode 100644 index 00000000..93b6ff7b --- /dev/null +++ b/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownTextManagerInterface.java @@ -0,0 +1,32 @@ +/** +* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). +* +* Do not edit this file as changes may cause incorrect behavior and will be lost +* once the code is regenerated. +* +* @generated by codegen project: GeneratePropsJavaInterface.js +*/ + +package com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import com.facebook.react.bridge.ReadableArray; +import com.facebook.react.bridge.ReadableMap; +import com.facebook.react.uimanager.ViewManagerWithGeneratedInterface; + +public interface EnrichedMarkdownTextManagerInterface extends ViewManagerWithGeneratedInterface { + void setMarkdown(T view, @Nullable String value); + void setMarkdownStyle(T view, @Nullable ReadableMap value); + void setEnableLinkPreview(T view, boolean value); + void setSelectable(T view, boolean value); + void setSelectionColor(T view, @Nullable Integer value); + void setSelectionHandleColor(T view, @Nullable Integer value); + void setMd4cFlags(T view, @Nullable ReadableMap value); + void setAllowFontScaling(T view, boolean value); + void setMaxFontSizeMultiplier(T view, float value); + void setAllowTrailingMargin(T view, boolean value); + void setStreamingAnimation(T view, boolean value); + void setSpoilerOverlay(T view, @Nullable String value); + void setContextMenuItems(T view, @Nullable ReadableArray value); +} diff --git a/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/ComponentDescriptors.cpp b/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/ComponentDescriptors.cpp new file mode 100644 index 00000000..4d59d519 --- /dev/null +++ b/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/ComponentDescriptors.cpp @@ -0,0 +1,22 @@ + +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateComponentDescriptorCpp.js + */ + +#include "ComponentDescriptors.h" +#include +#include + +namespace facebook::react { + +void EnrichedMarkdownTextSpec_registerComponentDescriptorsFromCodegen( + std::shared_ptr registry) { + +} + +} // namespace facebook::react diff --git a/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/ComponentDescriptors.h b/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/ComponentDescriptors.h new file mode 100644 index 00000000..06510880 --- /dev/null +++ b/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/ComponentDescriptors.h @@ -0,0 +1,24 @@ + +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateComponentDescriptorH.js + */ + +#pragma once + +#include "ShadowNodes.h" +#include +#include + +namespace facebook::react { + + + +void EnrichedMarkdownTextSpec_registerComponentDescriptorsFromCodegen( + std::shared_ptr registry); + +} // namespace facebook::react diff --git a/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/EventEmitters.cpp b/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/EventEmitters.cpp new file mode 100644 index 00000000..d3570ab7 --- /dev/null +++ b/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/EventEmitters.cpp @@ -0,0 +1,314 @@ + +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateEventEmitterCpp.js + */ + +#include "EventEmitters.h" + + +namespace facebook::react { + +void EnrichedMarkdownEventEmitter::onLinkPress(OnLinkPress event) const { + dispatchEvent("linkPress", [event=std::move(event)](jsi::Runtime &runtime) { + auto payload = jsi::Object(runtime); + payload.setProperty(runtime, "url", event.url); + return payload; + }); +} + + +void EnrichedMarkdownEventEmitter::onLinkLongPress(OnLinkLongPress event) const { + dispatchEvent("linkLongPress", [event=std::move(event)](jsi::Runtime &runtime) { + auto payload = jsi::Object(runtime); + payload.setProperty(runtime, "url", event.url); + return payload; + }); +} + + +void EnrichedMarkdownEventEmitter::onTaskListItemPress(OnTaskListItemPress event) const { + dispatchEvent("taskListItemPress", [event=std::move(event)](jsi::Runtime &runtime) { + auto payload = jsi::Object(runtime); + payload.setProperty(runtime, "index", event.index); +payload.setProperty(runtime, "checked", event.checked); +payload.setProperty(runtime, "text", event.text); + return payload; + }); +} + + +void EnrichedMarkdownEventEmitter::onMentionPress(OnMentionPress event) const { + dispatchEvent("mentionPress", [event=std::move(event)](jsi::Runtime &runtime) { + auto payload = jsi::Object(runtime); + payload.setProperty(runtime, "url", event.url); +payload.setProperty(runtime, "text", event.text); + return payload; + }); +} + + +void EnrichedMarkdownEventEmitter::onCitationPress(OnCitationPress event) const { + dispatchEvent("citationPress", [event=std::move(event)](jsi::Runtime &runtime) { + auto payload = jsi::Object(runtime); + payload.setProperty(runtime, "url", event.url); +payload.setProperty(runtime, "text", event.text); + return payload; + }); +} + + +void EnrichedMarkdownEventEmitter::onContextMenuItemPress(OnContextMenuItemPress event) const { + dispatchEvent("contextMenuItemPress", [event=std::move(event)](jsi::Runtime &runtime) { + auto payload = jsi::Object(runtime); + payload.setProperty(runtime, "itemText", event.itemText); +payload.setProperty(runtime, "selectedText", event.selectedText); +payload.setProperty(runtime, "selectionStart", event.selectionStart); +payload.setProperty(runtime, "selectionEnd", event.selectionEnd); + return payload; + }); +} + + +void EnrichedMarkdownTextInputEventEmitter::onChangeText(OnChangeText event) const { + dispatchEvent("changeText", [event=std::move(event)](jsi::Runtime &runtime) { + auto payload = jsi::Object(runtime); + payload.setProperty(runtime, "value", event.value); + return payload; + }); +} + + +void EnrichedMarkdownTextInputEventEmitter::onChangeMarkdown(OnChangeMarkdown event) const { + dispatchEvent("changeMarkdown", [event=std::move(event)](jsi::Runtime &runtime) { + auto payload = jsi::Object(runtime); + payload.setProperty(runtime, "value", event.value); + return payload; + }); +} + + +void EnrichedMarkdownTextInputEventEmitter::onChangeSelection(OnChangeSelection event) const { + dispatchEvent("changeSelection", [event=std::move(event)](jsi::Runtime &runtime) { + auto payload = jsi::Object(runtime); + payload.setProperty(runtime, "start", event.start); +payload.setProperty(runtime, "end", event.end); + return payload; + }); +} + + +void EnrichedMarkdownTextInputEventEmitter::onChangeState(OnChangeState event) const { + dispatchEvent("changeState", [event=std::move(event)](jsi::Runtime &runtime) { + auto payload = jsi::Object(runtime); + { + auto bold = jsi::Object(runtime); + bold.setProperty(runtime, "isActive", event.bold.isActive); + payload.setProperty(runtime, "bold", bold); +} +{ + auto italic = jsi::Object(runtime); + italic.setProperty(runtime, "isActive", event.italic.isActive); + payload.setProperty(runtime, "italic", italic); +} +{ + auto underline = jsi::Object(runtime); + underline.setProperty(runtime, "isActive", event.underline.isActive); + payload.setProperty(runtime, "underline", underline); +} +{ + auto strikethrough = jsi::Object(runtime); + strikethrough.setProperty(runtime, "isActive", event.strikethrough.isActive); + payload.setProperty(runtime, "strikethrough", strikethrough); +} +{ + auto spoiler = jsi::Object(runtime); + spoiler.setProperty(runtime, "isActive", event.spoiler.isActive); + payload.setProperty(runtime, "spoiler", spoiler); +} +{ + auto link = jsi::Object(runtime); + link.setProperty(runtime, "isActive", event.link.isActive); + payload.setProperty(runtime, "link", link); +} + return payload; + }); +} + + +void EnrichedMarkdownTextInputEventEmitter::onInputFocus(OnInputFocus event) const { + dispatchEvent("inputFocus", [event=std::move(event)](jsi::Runtime &runtime) { + auto payload = jsi::Object(runtime); + payload.setProperty(runtime, "target", event.target); + return payload; + }); +} + + +void EnrichedMarkdownTextInputEventEmitter::onInputBlur(OnInputBlur event) const { + dispatchEvent("inputBlur", [event=std::move(event)](jsi::Runtime &runtime) { + auto payload = jsi::Object(runtime); + payload.setProperty(runtime, "target", event.target); + return payload; + }); +} + + +void EnrichedMarkdownTextInputEventEmitter::onRequestMarkdownResult(OnRequestMarkdownResult event) const { + dispatchEvent("requestMarkdownResult", [event=std::move(event)](jsi::Runtime &runtime) { + auto payload = jsi::Object(runtime); + payload.setProperty(runtime, "requestId", event.requestId); +payload.setProperty(runtime, "markdown", event.markdown); + return payload; + }); +} + + +void EnrichedMarkdownTextInputEventEmitter::onRequestCaretRectResult(OnRequestCaretRectResult event) const { + dispatchEvent("requestCaretRectResult", [event=std::move(event)](jsi::Runtime &runtime) { + auto payload = jsi::Object(runtime); + payload.setProperty(runtime, "requestId", event.requestId); +payload.setProperty(runtime, "x", event.x); +payload.setProperty(runtime, "y", event.y); +payload.setProperty(runtime, "width", event.width); +payload.setProperty(runtime, "height", event.height); + return payload; + }); +} + + +void EnrichedMarkdownTextInputEventEmitter::onCaretRectChange(OnCaretRectChange event) const { + dispatchEvent("caretRectChange", [event=std::move(event)](jsi::Runtime &runtime) { + auto payload = jsi::Object(runtime); + payload.setProperty(runtime, "x", event.x); +payload.setProperty(runtime, "y", event.y); +payload.setProperty(runtime, "width", event.width); +payload.setProperty(runtime, "height", event.height); + return payload; + }); +} + + +void EnrichedMarkdownTextInputEventEmitter::onContextMenuItemPress(OnContextMenuItemPress event) const { + dispatchEvent("contextMenuItemPress", [event=std::move(event)](jsi::Runtime &runtime) { + auto payload = jsi::Object(runtime); + payload.setProperty(runtime, "itemText", event.itemText); +payload.setProperty(runtime, "selectedText", event.selectedText); +payload.setProperty(runtime, "selectionStart", event.selectionStart); +payload.setProperty(runtime, "selectionEnd", event.selectionEnd); +{ + auto styleState = jsi::Object(runtime); + { + auto bold = jsi::Object(runtime); + bold.setProperty(runtime, "isActive", event.styleState.bold.isActive); + styleState.setProperty(runtime, "bold", bold); + } + { + auto italic = jsi::Object(runtime); + italic.setProperty(runtime, "isActive", event.styleState.italic.isActive); + styleState.setProperty(runtime, "italic", italic); + } + { + auto underline = jsi::Object(runtime); + underline.setProperty(runtime, "isActive", event.styleState.underline.isActive); + styleState.setProperty(runtime, "underline", underline); + } + { + auto strikethrough = jsi::Object(runtime); + strikethrough.setProperty(runtime, "isActive", event.styleState.strikethrough.isActive); + styleState.setProperty(runtime, "strikethrough", strikethrough); + } + { + auto spoiler = jsi::Object(runtime); + spoiler.setProperty(runtime, "isActive", event.styleState.spoiler.isActive); + styleState.setProperty(runtime, "spoiler", spoiler); + } + { + auto link = jsi::Object(runtime); + link.setProperty(runtime, "isActive", event.styleState.link.isActive); + styleState.setProperty(runtime, "link", link); + } + payload.setProperty(runtime, "styleState", styleState); +} + return payload; + }); +} + + +void EnrichedMarkdownTextInputEventEmitter::onLinkDetected(OnLinkDetected event) const { + dispatchEvent("linkDetected", [event=std::move(event)](jsi::Runtime &runtime) { + auto payload = jsi::Object(runtime); + payload.setProperty(runtime, "text", event.text); +payload.setProperty(runtime, "url", event.url); +payload.setProperty(runtime, "start", event.start); +payload.setProperty(runtime, "end", event.end); + return payload; + }); +} + + +void EnrichedMarkdownTextEventEmitter::onLinkPress(OnLinkPress event) const { + dispatchEvent("linkPress", [event=std::move(event)](jsi::Runtime &runtime) { + auto payload = jsi::Object(runtime); + payload.setProperty(runtime, "url", event.url); + return payload; + }); +} + + +void EnrichedMarkdownTextEventEmitter::onLinkLongPress(OnLinkLongPress event) const { + dispatchEvent("linkLongPress", [event=std::move(event)](jsi::Runtime &runtime) { + auto payload = jsi::Object(runtime); + payload.setProperty(runtime, "url", event.url); + return payload; + }); +} + + +void EnrichedMarkdownTextEventEmitter::onTaskListItemPress(OnTaskListItemPress event) const { + dispatchEvent("taskListItemPress", [event=std::move(event)](jsi::Runtime &runtime) { + auto payload = jsi::Object(runtime); + payload.setProperty(runtime, "index", event.index); +payload.setProperty(runtime, "checked", event.checked); +payload.setProperty(runtime, "text", event.text); + return payload; + }); +} + + +void EnrichedMarkdownTextEventEmitter::onMentionPress(OnMentionPress event) const { + dispatchEvent("mentionPress", [event=std::move(event)](jsi::Runtime &runtime) { + auto payload = jsi::Object(runtime); + payload.setProperty(runtime, "url", event.url); +payload.setProperty(runtime, "text", event.text); + return payload; + }); +} + + +void EnrichedMarkdownTextEventEmitter::onCitationPress(OnCitationPress event) const { + dispatchEvent("citationPress", [event=std::move(event)](jsi::Runtime &runtime) { + auto payload = jsi::Object(runtime); + payload.setProperty(runtime, "url", event.url); +payload.setProperty(runtime, "text", event.text); + return payload; + }); +} + + +void EnrichedMarkdownTextEventEmitter::onContextMenuItemPress(OnContextMenuItemPress event) const { + dispatchEvent("contextMenuItemPress", [event=std::move(event)](jsi::Runtime &runtime) { + auto payload = jsi::Object(runtime); + payload.setProperty(runtime, "itemText", event.itemText); +payload.setProperty(runtime, "selectedText", event.selectedText); +payload.setProperty(runtime, "selectionStart", event.selectionStart); +payload.setProperty(runtime, "selectionEnd", event.selectionEnd); + return payload; + }); +} + +} // namespace facebook::react diff --git a/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/EventEmitters.h b/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/EventEmitters.h new file mode 100644 index 00000000..a0421da6 --- /dev/null +++ b/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/EventEmitters.h @@ -0,0 +1,255 @@ + +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateEventEmitterH.js + */ +#pragma once + +#include + + +namespace facebook::react { +class EnrichedMarkdownEventEmitter : public ViewEventEmitter { + public: + using ViewEventEmitter::ViewEventEmitter; + + struct OnLinkPress { + std::string url; + }; + + struct OnLinkLongPress { + std::string url; + }; + + struct OnTaskListItemPress { + int index; + bool checked; + std::string text; + }; + + struct OnMentionPress { + std::string url; + std::string text; + }; + + struct OnCitationPress { + std::string url; + std::string text; + }; + + struct OnContextMenuItemPress { + std::string itemText; + std::string selectedText; + int selectionStart; + int selectionEnd; + }; + void onLinkPress(OnLinkPress value) const; + + void onLinkLongPress(OnLinkLongPress value) const; + + void onTaskListItemPress(OnTaskListItemPress value) const; + + void onMentionPress(OnMentionPress value) const; + + void onCitationPress(OnCitationPress value) const; + + void onContextMenuItemPress(OnContextMenuItemPress value) const; +}; +class EnrichedMarkdownTextInputEventEmitter : public ViewEventEmitter { + public: + using ViewEventEmitter::ViewEventEmitter; + + struct OnChangeText { + std::string value; + }; + + struct OnChangeMarkdown { + std::string value; + }; + + struct OnChangeSelection { + int start; + int end; + }; + + struct OnChangeStateBold { + bool isActive; + }; + + struct OnChangeStateItalic { + bool isActive; + }; + + struct OnChangeStateUnderline { + bool isActive; + }; + + struct OnChangeStateStrikethrough { + bool isActive; + }; + + struct OnChangeStateSpoiler { + bool isActive; + }; + + struct OnChangeStateLink { + bool isActive; + }; + + struct OnChangeState { + OnChangeStateBold bold; + OnChangeStateItalic italic; + OnChangeStateUnderline underline; + OnChangeStateStrikethrough strikethrough; + OnChangeStateSpoiler spoiler; + OnChangeStateLink link; + }; + + struct OnInputFocus { + int target; + }; + + struct OnInputBlur { + int target; + }; + + struct OnRequestMarkdownResult { + int requestId; + std::string markdown; + }; + + struct OnRequestCaretRectResult { + int requestId; + double x; + double y; + double width; + double height; + }; + + struct OnCaretRectChange { + double x; + double y; + double width; + double height; + }; + + struct OnContextMenuItemPressStyleStateBold { + bool isActive; + }; + + struct OnContextMenuItemPressStyleStateItalic { + bool isActive; + }; + + struct OnContextMenuItemPressStyleStateUnderline { + bool isActive; + }; + + struct OnContextMenuItemPressStyleStateStrikethrough { + bool isActive; + }; + + struct OnContextMenuItemPressStyleStateSpoiler { + bool isActive; + }; + + struct OnContextMenuItemPressStyleStateLink { + bool isActive; + }; + + struct OnContextMenuItemPressStyleState { + OnContextMenuItemPressStyleStateBold bold; + OnContextMenuItemPressStyleStateItalic italic; + OnContextMenuItemPressStyleStateUnderline underline; + OnContextMenuItemPressStyleStateStrikethrough strikethrough; + OnContextMenuItemPressStyleStateSpoiler spoiler; + OnContextMenuItemPressStyleStateLink link; + }; + + struct OnContextMenuItemPress { + std::string itemText; + std::string selectedText; + int selectionStart; + int selectionEnd; + OnContextMenuItemPressStyleState styleState; + }; + + struct OnLinkDetected { + std::string text; + std::string url; + int start; + int end; + }; + void onChangeText(OnChangeText value) const; + + void onChangeMarkdown(OnChangeMarkdown value) const; + + void onChangeSelection(OnChangeSelection value) const; + + void onChangeState(OnChangeState value) const; + + void onInputFocus(OnInputFocus value) const; + + void onInputBlur(OnInputBlur value) const; + + void onRequestMarkdownResult(OnRequestMarkdownResult value) const; + + void onRequestCaretRectResult(OnRequestCaretRectResult value) const; + + void onCaretRectChange(OnCaretRectChange value) const; + + void onContextMenuItemPress(OnContextMenuItemPress value) const; + + void onLinkDetected(OnLinkDetected value) const; +}; +class EnrichedMarkdownTextEventEmitter : public ViewEventEmitter { + public: + using ViewEventEmitter::ViewEventEmitter; + + struct OnLinkPress { + std::string url; + }; + + struct OnLinkLongPress { + std::string url; + }; + + struct OnTaskListItemPress { + int index; + bool checked; + std::string text; + }; + + struct OnMentionPress { + std::string url; + std::string text; + }; + + struct OnCitationPress { + std::string url; + std::string text; + }; + + struct OnContextMenuItemPress { + std::string itemText; + std::string selectedText; + int selectionStart; + int selectionEnd; + }; + void onLinkPress(OnLinkPress value) const; + + void onLinkLongPress(OnLinkLongPress value) const; + + void onTaskListItemPress(OnTaskListItemPress value) const; + + void onMentionPress(OnMentionPress value) const; + + void onCitationPress(OnCitationPress value) const; + + void onContextMenuItemPress(OnContextMenuItemPress value) const; +}; +} // namespace facebook::react diff --git a/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/Props.cpp b/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/Props.cpp new file mode 100644 index 00000000..0b4e8f2f --- /dev/null +++ b/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/Props.cpp @@ -0,0 +1,315 @@ + +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GeneratePropsCpp.js + */ + +#include "Props.h" +#include +#include + +namespace facebook::react { + +EnrichedMarkdownProps::EnrichedMarkdownProps( + const PropsParserContext &context, + const EnrichedMarkdownProps &sourceProps, + const RawProps &rawProps): ViewProps(context, sourceProps, rawProps), + + markdown(convertRawProp(context, rawProps, "markdown", sourceProps.markdown, {})), + markdownStyle(convertRawProp(context, rawProps, "markdownStyle", sourceProps.markdownStyle, {})), + enableLinkPreview(convertRawProp(context, rawProps, "enableLinkPreview", sourceProps.enableLinkPreview, {true})), + selectable(convertRawProp(context, rawProps, "selectable", sourceProps.selectable, {false})), + selectionColor(convertRawProp(context, rawProps, "selectionColor", sourceProps.selectionColor, {})), + selectionHandleColor(convertRawProp(context, rawProps, "selectionHandleColor", sourceProps.selectionHandleColor, {})), + md4cFlags(convertRawProp(context, rawProps, "md4cFlags", sourceProps.md4cFlags, {})), + allowFontScaling(convertRawProp(context, rawProps, "allowFontScaling", sourceProps.allowFontScaling, {true})), + maxFontSizeMultiplier(convertRawProp(context, rawProps, "maxFontSizeMultiplier", sourceProps.maxFontSizeMultiplier, {0.0})), + allowTrailingMargin(convertRawProp(context, rawProps, "allowTrailingMargin", sourceProps.allowTrailingMargin, {false})), + streamingAnimation(convertRawProp(context, rawProps, "streamingAnimation", sourceProps.streamingAnimation, {false})), + spoilerOverlay(convertRawProp(context, rawProps, "spoilerOverlay", sourceProps.spoilerOverlay, {std::string{"particles"}})), + contextMenuItems(convertRawProp(context, rawProps, "contextMenuItems", sourceProps.contextMenuItems, {})) {} + +#ifdef RN_SERIALIZABLE_STATE +ComponentName EnrichedMarkdownProps::getDiffPropsImplementationTarget() const { + return "EnrichedMarkdown"; +} + +folly::dynamic EnrichedMarkdownProps::getDiffProps( + const Props* prevProps) const { + static const auto defaultProps = EnrichedMarkdownProps(); + const EnrichedMarkdownProps* oldProps = prevProps == nullptr + ? &defaultProps + : static_cast(prevProps); + if (this == oldProps) { + return folly::dynamic::object(); + } + folly::dynamic result = HostPlatformViewProps::getDiffProps(prevProps); + + if (markdown != oldProps->markdown) { + result["markdown"] = markdown; + } + + if (markdownStyle != oldProps->markdownStyle) { + result["markdownStyle"] = toDynamic(markdownStyle); + } + + if (enableLinkPreview != oldProps->enableLinkPreview) { + result["enableLinkPreview"] = enableLinkPreview; + } + + if (selectable != oldProps->selectable) { + result["selectable"] = selectable; + } + + if (selectionColor != oldProps->selectionColor) { + result["selectionColor"] = *selectionColor; + } + + if (selectionHandleColor != oldProps->selectionHandleColor) { + result["selectionHandleColor"] = *selectionHandleColor; + } + + if (md4cFlags != oldProps->md4cFlags) { + result["md4cFlags"] = toDynamic(md4cFlags); + } + + if (allowFontScaling != oldProps->allowFontScaling) { + result["allowFontScaling"] = allowFontScaling; + } + + if ((maxFontSizeMultiplier != oldProps->maxFontSizeMultiplier) && !(std::isnan(maxFontSizeMultiplier) && std::isnan(oldProps->maxFontSizeMultiplier))) { + result["maxFontSizeMultiplier"] = maxFontSizeMultiplier; + } + + if (allowTrailingMargin != oldProps->allowTrailingMargin) { + result["allowTrailingMargin"] = allowTrailingMargin; + } + + if (streamingAnimation != oldProps->streamingAnimation) { + result["streamingAnimation"] = streamingAnimation; + } + + if (spoilerOverlay != oldProps->spoilerOverlay) { + result["spoilerOverlay"] = spoilerOverlay; + } + + if (contextMenuItems != oldProps->contextMenuItems) { + result["contextMenuItems"] = toDynamic(contextMenuItems); + } + return result; +} +#endif +EnrichedMarkdownTextInputProps::EnrichedMarkdownTextInputProps( + const PropsParserContext &context, + const EnrichedMarkdownTextInputProps &sourceProps, + const RawProps &rawProps): ViewProps(context, sourceProps, rawProps), + + defaultValue(convertRawProp(context, rawProps, "defaultValue", sourceProps.defaultValue, {})), + placeholder(convertRawProp(context, rawProps, "placeholder", sourceProps.placeholder, {})), + placeholderTextColor(convertRawProp(context, rawProps, "placeholderTextColor", sourceProps.placeholderTextColor, {})), + editable(convertRawProp(context, rawProps, "editable", sourceProps.editable, {false})), + autoFocus(convertRawProp(context, rawProps, "autoFocus", sourceProps.autoFocus, {false})), + scrollEnabled(convertRawProp(context, rawProps, "scrollEnabled", sourceProps.scrollEnabled, {false})), + autoCapitalize(convertRawProp(context, rawProps, "autoCapitalize", sourceProps.autoCapitalize, {})), + multiline(convertRawProp(context, rawProps, "multiline", sourceProps.multiline, {false})), + cursorColor(convertRawProp(context, rawProps, "cursorColor", sourceProps.cursorColor, {})), + selectionColor(convertRawProp(context, rawProps, "selectionColor", sourceProps.selectionColor, {})), + markdownStyle(convertRawProp(context, rawProps, "markdownStyle", sourceProps.markdownStyle, {})), + color(convertRawProp(context, rawProps, "color", sourceProps.color, {})), + fontSize(convertRawProp(context, rawProps, "fontSize", sourceProps.fontSize, {0.0})), + lineHeight(convertRawProp(context, rawProps, "lineHeight", sourceProps.lineHeight, {0.0})), + fontFamily(convertRawProp(context, rawProps, "fontFamily", sourceProps.fontFamily, {})), + fontWeight(convertRawProp(context, rawProps, "fontWeight", sourceProps.fontWeight, {})), + isOnChangeMarkdownSet(convertRawProp(context, rawProps, "isOnChangeMarkdownSet", sourceProps.isOnChangeMarkdownSet, {false})), + contextMenuItems(convertRawProp(context, rawProps, "contextMenuItems", sourceProps.contextMenuItems, {})), + linkRegex(convertRawProp(context, rawProps, "linkRegex", sourceProps.linkRegex, {})) {} + +#ifdef RN_SERIALIZABLE_STATE +ComponentName EnrichedMarkdownTextInputProps::getDiffPropsImplementationTarget() const { + return "EnrichedMarkdownTextInput"; +} + +folly::dynamic EnrichedMarkdownTextInputProps::getDiffProps( + const Props* prevProps) const { + static const auto defaultProps = EnrichedMarkdownTextInputProps(); + const EnrichedMarkdownTextInputProps* oldProps = prevProps == nullptr + ? &defaultProps + : static_cast(prevProps); + if (this == oldProps) { + return folly::dynamic::object(); + } + folly::dynamic result = HostPlatformViewProps::getDiffProps(prevProps); + + if (defaultValue != oldProps->defaultValue) { + result["defaultValue"] = defaultValue; + } + + if (placeholder != oldProps->placeholder) { + result["placeholder"] = placeholder; + } + + if (placeholderTextColor != oldProps->placeholderTextColor) { + result["placeholderTextColor"] = *placeholderTextColor; + } + + if (editable != oldProps->editable) { + result["editable"] = editable; + } + + if (autoFocus != oldProps->autoFocus) { + result["autoFocus"] = autoFocus; + } + + if (scrollEnabled != oldProps->scrollEnabled) { + result["scrollEnabled"] = scrollEnabled; + } + + if (autoCapitalize != oldProps->autoCapitalize) { + result["autoCapitalize"] = autoCapitalize; + } + + if (multiline != oldProps->multiline) { + result["multiline"] = multiline; + } + + if (cursorColor != oldProps->cursorColor) { + result["cursorColor"] = *cursorColor; + } + + if (selectionColor != oldProps->selectionColor) { + result["selectionColor"] = *selectionColor; + } + + if (markdownStyle != oldProps->markdownStyle) { + result["markdownStyle"] = toDynamic(markdownStyle); + } + + if (color != oldProps->color) { + result["color"] = *color; + } + + if ((fontSize != oldProps->fontSize) && !(std::isnan(fontSize) && std::isnan(oldProps->fontSize))) { + result["fontSize"] = fontSize; + } + + if ((lineHeight != oldProps->lineHeight) && !(std::isnan(lineHeight) && std::isnan(oldProps->lineHeight))) { + result["lineHeight"] = lineHeight; + } + + if (fontFamily != oldProps->fontFamily) { + result["fontFamily"] = fontFamily; + } + + if (fontWeight != oldProps->fontWeight) { + result["fontWeight"] = fontWeight; + } + + if (isOnChangeMarkdownSet != oldProps->isOnChangeMarkdownSet) { + result["isOnChangeMarkdownSet"] = isOnChangeMarkdownSet; + } + + if (contextMenuItems != oldProps->contextMenuItems) { + result["contextMenuItems"] = toDynamic(contextMenuItems); + } + + if (linkRegex != oldProps->linkRegex) { + result["linkRegex"] = toDynamic(linkRegex); + } + return result; +} +#endif +EnrichedMarkdownTextProps::EnrichedMarkdownTextProps( + const PropsParserContext &context, + const EnrichedMarkdownTextProps &sourceProps, + const RawProps &rawProps): ViewProps(context, sourceProps, rawProps), + + markdown(convertRawProp(context, rawProps, "markdown", sourceProps.markdown, {})), + markdownStyle(convertRawProp(context, rawProps, "markdownStyle", sourceProps.markdownStyle, {})), + enableLinkPreview(convertRawProp(context, rawProps, "enableLinkPreview", sourceProps.enableLinkPreview, {true})), + selectable(convertRawProp(context, rawProps, "selectable", sourceProps.selectable, {false})), + selectionColor(convertRawProp(context, rawProps, "selectionColor", sourceProps.selectionColor, {})), + selectionHandleColor(convertRawProp(context, rawProps, "selectionHandleColor", sourceProps.selectionHandleColor, {})), + md4cFlags(convertRawProp(context, rawProps, "md4cFlags", sourceProps.md4cFlags, {})), + allowFontScaling(convertRawProp(context, rawProps, "allowFontScaling", sourceProps.allowFontScaling, {true})), + maxFontSizeMultiplier(convertRawProp(context, rawProps, "maxFontSizeMultiplier", sourceProps.maxFontSizeMultiplier, {0.0})), + allowTrailingMargin(convertRawProp(context, rawProps, "allowTrailingMargin", sourceProps.allowTrailingMargin, {false})), + streamingAnimation(convertRawProp(context, rawProps, "streamingAnimation", sourceProps.streamingAnimation, {false})), + spoilerOverlay(convertRawProp(context, rawProps, "spoilerOverlay", sourceProps.spoilerOverlay, {std::string{"particles"}})), + contextMenuItems(convertRawProp(context, rawProps, "contextMenuItems", sourceProps.contextMenuItems, {})) {} + +#ifdef RN_SERIALIZABLE_STATE +ComponentName EnrichedMarkdownTextProps::getDiffPropsImplementationTarget() const { + return "EnrichedMarkdownText"; +} + +folly::dynamic EnrichedMarkdownTextProps::getDiffProps( + const Props* prevProps) const { + static const auto defaultProps = EnrichedMarkdownTextProps(); + const EnrichedMarkdownTextProps* oldProps = prevProps == nullptr + ? &defaultProps + : static_cast(prevProps); + if (this == oldProps) { + return folly::dynamic::object(); + } + folly::dynamic result = HostPlatformViewProps::getDiffProps(prevProps); + + if (markdown != oldProps->markdown) { + result["markdown"] = markdown; + } + + if (markdownStyle != oldProps->markdownStyle) { + result["markdownStyle"] = toDynamic(markdownStyle); + } + + if (enableLinkPreview != oldProps->enableLinkPreview) { + result["enableLinkPreview"] = enableLinkPreview; + } + + if (selectable != oldProps->selectable) { + result["selectable"] = selectable; + } + + if (selectionColor != oldProps->selectionColor) { + result["selectionColor"] = *selectionColor; + } + + if (selectionHandleColor != oldProps->selectionHandleColor) { + result["selectionHandleColor"] = *selectionHandleColor; + } + + if (md4cFlags != oldProps->md4cFlags) { + result["md4cFlags"] = toDynamic(md4cFlags); + } + + if (allowFontScaling != oldProps->allowFontScaling) { + result["allowFontScaling"] = allowFontScaling; + } + + if ((maxFontSizeMultiplier != oldProps->maxFontSizeMultiplier) && !(std::isnan(maxFontSizeMultiplier) && std::isnan(oldProps->maxFontSizeMultiplier))) { + result["maxFontSizeMultiplier"] = maxFontSizeMultiplier; + } + + if (allowTrailingMargin != oldProps->allowTrailingMargin) { + result["allowTrailingMargin"] = allowTrailingMargin; + } + + if (streamingAnimation != oldProps->streamingAnimation) { + result["streamingAnimation"] = streamingAnimation; + } + + if (spoilerOverlay != oldProps->spoilerOverlay) { + result["spoilerOverlay"] = spoilerOverlay; + } + + if (contextMenuItems != oldProps->contextMenuItems) { + result["contextMenuItems"] = toDynamic(contextMenuItems); + } + return result; +} +#endif + +} // namespace facebook::react diff --git a/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/Props.h b/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/Props.h new file mode 100644 index 00000000..659b7066 --- /dev/null +++ b/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/Props.h @@ -0,0 +1,4674 @@ + +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GeneratePropsH.js + */ +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace facebook::react { + +struct EnrichedMarkdownMarkdownStyleParagraphStruct { + Float fontSize{0.0}; + std::string fontFamily{}; + std::string fontWeight{}; + SharedColor color{}; + Float marginTop{0.0}; + Float marginBottom{0.0}; + Float lineHeight{0.0}; + std::string textAlign{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownMarkdownStyleParagraphStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["fontSize"] = fontSize; + result["fontFamily"] = fontFamily; + result["fontWeight"] = fontWeight; + result["color"] = ::facebook::react::toDynamic(color); + result["marginTop"] = marginTop; + result["marginBottom"] = marginBottom; + result["lineHeight"] = lineHeight; + result["textAlign"] = textAlign; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownMarkdownStyleParagraphStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_fontSize = map.find("fontSize"); + if (tmp_fontSize != map.end()) { + fromRawValue(context, tmp_fontSize->second, result.fontSize); + } + auto tmp_fontFamily = map.find("fontFamily"); + if (tmp_fontFamily != map.end()) { + fromRawValue(context, tmp_fontFamily->second, result.fontFamily); + } + auto tmp_fontWeight = map.find("fontWeight"); + if (tmp_fontWeight != map.end()) { + fromRawValue(context, tmp_fontWeight->second, result.fontWeight); + } + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } + auto tmp_marginTop = map.find("marginTop"); + if (tmp_marginTop != map.end()) { + fromRawValue(context, tmp_marginTop->second, result.marginTop); + } + auto tmp_marginBottom = map.find("marginBottom"); + if (tmp_marginBottom != map.end()) { + fromRawValue(context, tmp_marginBottom->second, result.marginBottom); + } + auto tmp_lineHeight = map.find("lineHeight"); + if (tmp_lineHeight != map.end()) { + fromRawValue(context, tmp_lineHeight->second, result.lineHeight); + } + auto tmp_textAlign = map.find("textAlign"); + if (tmp_textAlign != map.end()) { + fromRawValue(context, tmp_textAlign->second, result.textAlign); + } +} + +static inline std::string toString(const EnrichedMarkdownMarkdownStyleParagraphStruct &value) { + return "[Object EnrichedMarkdownMarkdownStyleParagraphStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownMarkdownStyleParagraphStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownMarkdownStyleH1Struct { + Float fontSize{0.0}; + std::string fontFamily{}; + std::string fontWeight{}; + SharedColor color{}; + Float marginTop{0.0}; + Float marginBottom{0.0}; + Float lineHeight{0.0}; + std::string textAlign{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownMarkdownStyleH1Struct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["fontSize"] = fontSize; + result["fontFamily"] = fontFamily; + result["fontWeight"] = fontWeight; + result["color"] = ::facebook::react::toDynamic(color); + result["marginTop"] = marginTop; + result["marginBottom"] = marginBottom; + result["lineHeight"] = lineHeight; + result["textAlign"] = textAlign; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownMarkdownStyleH1Struct &result) { + auto map = (std::unordered_map)value; + + auto tmp_fontSize = map.find("fontSize"); + if (tmp_fontSize != map.end()) { + fromRawValue(context, tmp_fontSize->second, result.fontSize); + } + auto tmp_fontFamily = map.find("fontFamily"); + if (tmp_fontFamily != map.end()) { + fromRawValue(context, tmp_fontFamily->second, result.fontFamily); + } + auto tmp_fontWeight = map.find("fontWeight"); + if (tmp_fontWeight != map.end()) { + fromRawValue(context, tmp_fontWeight->second, result.fontWeight); + } + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } + auto tmp_marginTop = map.find("marginTop"); + if (tmp_marginTop != map.end()) { + fromRawValue(context, tmp_marginTop->second, result.marginTop); + } + auto tmp_marginBottom = map.find("marginBottom"); + if (tmp_marginBottom != map.end()) { + fromRawValue(context, tmp_marginBottom->second, result.marginBottom); + } + auto tmp_lineHeight = map.find("lineHeight"); + if (tmp_lineHeight != map.end()) { + fromRawValue(context, tmp_lineHeight->second, result.lineHeight); + } + auto tmp_textAlign = map.find("textAlign"); + if (tmp_textAlign != map.end()) { + fromRawValue(context, tmp_textAlign->second, result.textAlign); + } +} + +static inline std::string toString(const EnrichedMarkdownMarkdownStyleH1Struct &value) { + return "[Object EnrichedMarkdownMarkdownStyleH1Struct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownMarkdownStyleH1Struct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownMarkdownStyleH2Struct { + Float fontSize{0.0}; + std::string fontFamily{}; + std::string fontWeight{}; + SharedColor color{}; + Float marginTop{0.0}; + Float marginBottom{0.0}; + Float lineHeight{0.0}; + std::string textAlign{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownMarkdownStyleH2Struct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["fontSize"] = fontSize; + result["fontFamily"] = fontFamily; + result["fontWeight"] = fontWeight; + result["color"] = ::facebook::react::toDynamic(color); + result["marginTop"] = marginTop; + result["marginBottom"] = marginBottom; + result["lineHeight"] = lineHeight; + result["textAlign"] = textAlign; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownMarkdownStyleH2Struct &result) { + auto map = (std::unordered_map)value; + + auto tmp_fontSize = map.find("fontSize"); + if (tmp_fontSize != map.end()) { + fromRawValue(context, tmp_fontSize->second, result.fontSize); + } + auto tmp_fontFamily = map.find("fontFamily"); + if (tmp_fontFamily != map.end()) { + fromRawValue(context, tmp_fontFamily->second, result.fontFamily); + } + auto tmp_fontWeight = map.find("fontWeight"); + if (tmp_fontWeight != map.end()) { + fromRawValue(context, tmp_fontWeight->second, result.fontWeight); + } + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } + auto tmp_marginTop = map.find("marginTop"); + if (tmp_marginTop != map.end()) { + fromRawValue(context, tmp_marginTop->second, result.marginTop); + } + auto tmp_marginBottom = map.find("marginBottom"); + if (tmp_marginBottom != map.end()) { + fromRawValue(context, tmp_marginBottom->second, result.marginBottom); + } + auto tmp_lineHeight = map.find("lineHeight"); + if (tmp_lineHeight != map.end()) { + fromRawValue(context, tmp_lineHeight->second, result.lineHeight); + } + auto tmp_textAlign = map.find("textAlign"); + if (tmp_textAlign != map.end()) { + fromRawValue(context, tmp_textAlign->second, result.textAlign); + } +} + +static inline std::string toString(const EnrichedMarkdownMarkdownStyleH2Struct &value) { + return "[Object EnrichedMarkdownMarkdownStyleH2Struct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownMarkdownStyleH2Struct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownMarkdownStyleH3Struct { + Float fontSize{0.0}; + std::string fontFamily{}; + std::string fontWeight{}; + SharedColor color{}; + Float marginTop{0.0}; + Float marginBottom{0.0}; + Float lineHeight{0.0}; + std::string textAlign{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownMarkdownStyleH3Struct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["fontSize"] = fontSize; + result["fontFamily"] = fontFamily; + result["fontWeight"] = fontWeight; + result["color"] = ::facebook::react::toDynamic(color); + result["marginTop"] = marginTop; + result["marginBottom"] = marginBottom; + result["lineHeight"] = lineHeight; + result["textAlign"] = textAlign; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownMarkdownStyleH3Struct &result) { + auto map = (std::unordered_map)value; + + auto tmp_fontSize = map.find("fontSize"); + if (tmp_fontSize != map.end()) { + fromRawValue(context, tmp_fontSize->second, result.fontSize); + } + auto tmp_fontFamily = map.find("fontFamily"); + if (tmp_fontFamily != map.end()) { + fromRawValue(context, tmp_fontFamily->second, result.fontFamily); + } + auto tmp_fontWeight = map.find("fontWeight"); + if (tmp_fontWeight != map.end()) { + fromRawValue(context, tmp_fontWeight->second, result.fontWeight); + } + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } + auto tmp_marginTop = map.find("marginTop"); + if (tmp_marginTop != map.end()) { + fromRawValue(context, tmp_marginTop->second, result.marginTop); + } + auto tmp_marginBottom = map.find("marginBottom"); + if (tmp_marginBottom != map.end()) { + fromRawValue(context, tmp_marginBottom->second, result.marginBottom); + } + auto tmp_lineHeight = map.find("lineHeight"); + if (tmp_lineHeight != map.end()) { + fromRawValue(context, tmp_lineHeight->second, result.lineHeight); + } + auto tmp_textAlign = map.find("textAlign"); + if (tmp_textAlign != map.end()) { + fromRawValue(context, tmp_textAlign->second, result.textAlign); + } +} + +static inline std::string toString(const EnrichedMarkdownMarkdownStyleH3Struct &value) { + return "[Object EnrichedMarkdownMarkdownStyleH3Struct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownMarkdownStyleH3Struct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownMarkdownStyleH4Struct { + Float fontSize{0.0}; + std::string fontFamily{}; + std::string fontWeight{}; + SharedColor color{}; + Float marginTop{0.0}; + Float marginBottom{0.0}; + Float lineHeight{0.0}; + std::string textAlign{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownMarkdownStyleH4Struct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["fontSize"] = fontSize; + result["fontFamily"] = fontFamily; + result["fontWeight"] = fontWeight; + result["color"] = ::facebook::react::toDynamic(color); + result["marginTop"] = marginTop; + result["marginBottom"] = marginBottom; + result["lineHeight"] = lineHeight; + result["textAlign"] = textAlign; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownMarkdownStyleH4Struct &result) { + auto map = (std::unordered_map)value; + + auto tmp_fontSize = map.find("fontSize"); + if (tmp_fontSize != map.end()) { + fromRawValue(context, tmp_fontSize->second, result.fontSize); + } + auto tmp_fontFamily = map.find("fontFamily"); + if (tmp_fontFamily != map.end()) { + fromRawValue(context, tmp_fontFamily->second, result.fontFamily); + } + auto tmp_fontWeight = map.find("fontWeight"); + if (tmp_fontWeight != map.end()) { + fromRawValue(context, tmp_fontWeight->second, result.fontWeight); + } + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } + auto tmp_marginTop = map.find("marginTop"); + if (tmp_marginTop != map.end()) { + fromRawValue(context, tmp_marginTop->second, result.marginTop); + } + auto tmp_marginBottom = map.find("marginBottom"); + if (tmp_marginBottom != map.end()) { + fromRawValue(context, tmp_marginBottom->second, result.marginBottom); + } + auto tmp_lineHeight = map.find("lineHeight"); + if (tmp_lineHeight != map.end()) { + fromRawValue(context, tmp_lineHeight->second, result.lineHeight); + } + auto tmp_textAlign = map.find("textAlign"); + if (tmp_textAlign != map.end()) { + fromRawValue(context, tmp_textAlign->second, result.textAlign); + } +} + +static inline std::string toString(const EnrichedMarkdownMarkdownStyleH4Struct &value) { + return "[Object EnrichedMarkdownMarkdownStyleH4Struct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownMarkdownStyleH4Struct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownMarkdownStyleH5Struct { + Float fontSize{0.0}; + std::string fontFamily{}; + std::string fontWeight{}; + SharedColor color{}; + Float marginTop{0.0}; + Float marginBottom{0.0}; + Float lineHeight{0.0}; + std::string textAlign{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownMarkdownStyleH5Struct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["fontSize"] = fontSize; + result["fontFamily"] = fontFamily; + result["fontWeight"] = fontWeight; + result["color"] = ::facebook::react::toDynamic(color); + result["marginTop"] = marginTop; + result["marginBottom"] = marginBottom; + result["lineHeight"] = lineHeight; + result["textAlign"] = textAlign; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownMarkdownStyleH5Struct &result) { + auto map = (std::unordered_map)value; + + auto tmp_fontSize = map.find("fontSize"); + if (tmp_fontSize != map.end()) { + fromRawValue(context, tmp_fontSize->second, result.fontSize); + } + auto tmp_fontFamily = map.find("fontFamily"); + if (tmp_fontFamily != map.end()) { + fromRawValue(context, tmp_fontFamily->second, result.fontFamily); + } + auto tmp_fontWeight = map.find("fontWeight"); + if (tmp_fontWeight != map.end()) { + fromRawValue(context, tmp_fontWeight->second, result.fontWeight); + } + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } + auto tmp_marginTop = map.find("marginTop"); + if (tmp_marginTop != map.end()) { + fromRawValue(context, tmp_marginTop->second, result.marginTop); + } + auto tmp_marginBottom = map.find("marginBottom"); + if (tmp_marginBottom != map.end()) { + fromRawValue(context, tmp_marginBottom->second, result.marginBottom); + } + auto tmp_lineHeight = map.find("lineHeight"); + if (tmp_lineHeight != map.end()) { + fromRawValue(context, tmp_lineHeight->second, result.lineHeight); + } + auto tmp_textAlign = map.find("textAlign"); + if (tmp_textAlign != map.end()) { + fromRawValue(context, tmp_textAlign->second, result.textAlign); + } +} + +static inline std::string toString(const EnrichedMarkdownMarkdownStyleH5Struct &value) { + return "[Object EnrichedMarkdownMarkdownStyleH5Struct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownMarkdownStyleH5Struct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownMarkdownStyleH6Struct { + Float fontSize{0.0}; + std::string fontFamily{}; + std::string fontWeight{}; + SharedColor color{}; + Float marginTop{0.0}; + Float marginBottom{0.0}; + Float lineHeight{0.0}; + std::string textAlign{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownMarkdownStyleH6Struct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["fontSize"] = fontSize; + result["fontFamily"] = fontFamily; + result["fontWeight"] = fontWeight; + result["color"] = ::facebook::react::toDynamic(color); + result["marginTop"] = marginTop; + result["marginBottom"] = marginBottom; + result["lineHeight"] = lineHeight; + result["textAlign"] = textAlign; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownMarkdownStyleH6Struct &result) { + auto map = (std::unordered_map)value; + + auto tmp_fontSize = map.find("fontSize"); + if (tmp_fontSize != map.end()) { + fromRawValue(context, tmp_fontSize->second, result.fontSize); + } + auto tmp_fontFamily = map.find("fontFamily"); + if (tmp_fontFamily != map.end()) { + fromRawValue(context, tmp_fontFamily->second, result.fontFamily); + } + auto tmp_fontWeight = map.find("fontWeight"); + if (tmp_fontWeight != map.end()) { + fromRawValue(context, tmp_fontWeight->second, result.fontWeight); + } + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } + auto tmp_marginTop = map.find("marginTop"); + if (tmp_marginTop != map.end()) { + fromRawValue(context, tmp_marginTop->second, result.marginTop); + } + auto tmp_marginBottom = map.find("marginBottom"); + if (tmp_marginBottom != map.end()) { + fromRawValue(context, tmp_marginBottom->second, result.marginBottom); + } + auto tmp_lineHeight = map.find("lineHeight"); + if (tmp_lineHeight != map.end()) { + fromRawValue(context, tmp_lineHeight->second, result.lineHeight); + } + auto tmp_textAlign = map.find("textAlign"); + if (tmp_textAlign != map.end()) { + fromRawValue(context, tmp_textAlign->second, result.textAlign); + } +} + +static inline std::string toString(const EnrichedMarkdownMarkdownStyleH6Struct &value) { + return "[Object EnrichedMarkdownMarkdownStyleH6Struct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownMarkdownStyleH6Struct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownMarkdownStyleBlockquoteStruct { + Float fontSize{0.0}; + std::string fontFamily{}; + std::string fontWeight{}; + SharedColor color{}; + Float marginTop{0.0}; + Float marginBottom{0.0}; + Float lineHeight{0.0}; + SharedColor borderColor{}; + Float borderWidth{0.0}; + Float gapWidth{0.0}; + SharedColor backgroundColor{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownMarkdownStyleBlockquoteStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["fontSize"] = fontSize; + result["fontFamily"] = fontFamily; + result["fontWeight"] = fontWeight; + result["color"] = ::facebook::react::toDynamic(color); + result["marginTop"] = marginTop; + result["marginBottom"] = marginBottom; + result["lineHeight"] = lineHeight; + result["borderColor"] = ::facebook::react::toDynamic(borderColor); + result["borderWidth"] = borderWidth; + result["gapWidth"] = gapWidth; + result["backgroundColor"] = ::facebook::react::toDynamic(backgroundColor); + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownMarkdownStyleBlockquoteStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_fontSize = map.find("fontSize"); + if (tmp_fontSize != map.end()) { + fromRawValue(context, tmp_fontSize->second, result.fontSize); + } + auto tmp_fontFamily = map.find("fontFamily"); + if (tmp_fontFamily != map.end()) { + fromRawValue(context, tmp_fontFamily->second, result.fontFamily); + } + auto tmp_fontWeight = map.find("fontWeight"); + if (tmp_fontWeight != map.end()) { + fromRawValue(context, tmp_fontWeight->second, result.fontWeight); + } + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } + auto tmp_marginTop = map.find("marginTop"); + if (tmp_marginTop != map.end()) { + fromRawValue(context, tmp_marginTop->second, result.marginTop); + } + auto tmp_marginBottom = map.find("marginBottom"); + if (tmp_marginBottom != map.end()) { + fromRawValue(context, tmp_marginBottom->second, result.marginBottom); + } + auto tmp_lineHeight = map.find("lineHeight"); + if (tmp_lineHeight != map.end()) { + fromRawValue(context, tmp_lineHeight->second, result.lineHeight); + } + auto tmp_borderColor = map.find("borderColor"); + if (tmp_borderColor != map.end()) { + fromRawValue(context, tmp_borderColor->second, result.borderColor); + } + auto tmp_borderWidth = map.find("borderWidth"); + if (tmp_borderWidth != map.end()) { + fromRawValue(context, tmp_borderWidth->second, result.borderWidth); + } + auto tmp_gapWidth = map.find("gapWidth"); + if (tmp_gapWidth != map.end()) { + fromRawValue(context, tmp_gapWidth->second, result.gapWidth); + } + auto tmp_backgroundColor = map.find("backgroundColor"); + if (tmp_backgroundColor != map.end()) { + fromRawValue(context, tmp_backgroundColor->second, result.backgroundColor); + } +} + +static inline std::string toString(const EnrichedMarkdownMarkdownStyleBlockquoteStruct &value) { + return "[Object EnrichedMarkdownMarkdownStyleBlockquoteStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownMarkdownStyleBlockquoteStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownMarkdownStyleListStruct { + Float fontSize{0.0}; + std::string fontFamily{}; + std::string fontWeight{}; + SharedColor color{}; + Float marginTop{0.0}; + Float marginBottom{0.0}; + Float lineHeight{0.0}; + SharedColor bulletColor{}; + Float bulletSize{0.0}; + Float markerMinWidth{0.0}; + SharedColor markerColor{}; + std::string markerFontWeight{}; + Float gapWidth{0.0}; + Float marginLeft{0.0}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownMarkdownStyleListStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["fontSize"] = fontSize; + result["fontFamily"] = fontFamily; + result["fontWeight"] = fontWeight; + result["color"] = ::facebook::react::toDynamic(color); + result["marginTop"] = marginTop; + result["marginBottom"] = marginBottom; + result["lineHeight"] = lineHeight; + result["bulletColor"] = ::facebook::react::toDynamic(bulletColor); + result["bulletSize"] = bulletSize; + result["markerMinWidth"] = markerMinWidth; + result["markerColor"] = ::facebook::react::toDynamic(markerColor); + result["markerFontWeight"] = markerFontWeight; + result["gapWidth"] = gapWidth; + result["marginLeft"] = marginLeft; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownMarkdownStyleListStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_fontSize = map.find("fontSize"); + if (tmp_fontSize != map.end()) { + fromRawValue(context, tmp_fontSize->second, result.fontSize); + } + auto tmp_fontFamily = map.find("fontFamily"); + if (tmp_fontFamily != map.end()) { + fromRawValue(context, tmp_fontFamily->second, result.fontFamily); + } + auto tmp_fontWeight = map.find("fontWeight"); + if (tmp_fontWeight != map.end()) { + fromRawValue(context, tmp_fontWeight->second, result.fontWeight); + } + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } + auto tmp_marginTop = map.find("marginTop"); + if (tmp_marginTop != map.end()) { + fromRawValue(context, tmp_marginTop->second, result.marginTop); + } + auto tmp_marginBottom = map.find("marginBottom"); + if (tmp_marginBottom != map.end()) { + fromRawValue(context, tmp_marginBottom->second, result.marginBottom); + } + auto tmp_lineHeight = map.find("lineHeight"); + if (tmp_lineHeight != map.end()) { + fromRawValue(context, tmp_lineHeight->second, result.lineHeight); + } + auto tmp_bulletColor = map.find("bulletColor"); + if (tmp_bulletColor != map.end()) { + fromRawValue(context, tmp_bulletColor->second, result.bulletColor); + } + auto tmp_bulletSize = map.find("bulletSize"); + if (tmp_bulletSize != map.end()) { + fromRawValue(context, tmp_bulletSize->second, result.bulletSize); + } + auto tmp_markerMinWidth = map.find("markerMinWidth"); + if (tmp_markerMinWidth != map.end()) { + fromRawValue(context, tmp_markerMinWidth->second, result.markerMinWidth); + } + auto tmp_markerColor = map.find("markerColor"); + if (tmp_markerColor != map.end()) { + fromRawValue(context, tmp_markerColor->second, result.markerColor); + } + auto tmp_markerFontWeight = map.find("markerFontWeight"); + if (tmp_markerFontWeight != map.end()) { + fromRawValue(context, tmp_markerFontWeight->second, result.markerFontWeight); + } + auto tmp_gapWidth = map.find("gapWidth"); + if (tmp_gapWidth != map.end()) { + fromRawValue(context, tmp_gapWidth->second, result.gapWidth); + } + auto tmp_marginLeft = map.find("marginLeft"); + if (tmp_marginLeft != map.end()) { + fromRawValue(context, tmp_marginLeft->second, result.marginLeft); + } +} + +static inline std::string toString(const EnrichedMarkdownMarkdownStyleListStruct &value) { + return "[Object EnrichedMarkdownMarkdownStyleListStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownMarkdownStyleListStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownMarkdownStyleCodeBlockStruct { + Float fontSize{0.0}; + std::string fontFamily{}; + std::string fontWeight{}; + SharedColor color{}; + Float marginTop{0.0}; + Float marginBottom{0.0}; + Float lineHeight{0.0}; + SharedColor backgroundColor{}; + SharedColor borderColor{}; + Float borderRadius{0.0}; + Float borderWidth{0.0}; + Float padding{0.0}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownMarkdownStyleCodeBlockStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["fontSize"] = fontSize; + result["fontFamily"] = fontFamily; + result["fontWeight"] = fontWeight; + result["color"] = ::facebook::react::toDynamic(color); + result["marginTop"] = marginTop; + result["marginBottom"] = marginBottom; + result["lineHeight"] = lineHeight; + result["backgroundColor"] = ::facebook::react::toDynamic(backgroundColor); + result["borderColor"] = ::facebook::react::toDynamic(borderColor); + result["borderRadius"] = borderRadius; + result["borderWidth"] = borderWidth; + result["padding"] = padding; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownMarkdownStyleCodeBlockStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_fontSize = map.find("fontSize"); + if (tmp_fontSize != map.end()) { + fromRawValue(context, tmp_fontSize->second, result.fontSize); + } + auto tmp_fontFamily = map.find("fontFamily"); + if (tmp_fontFamily != map.end()) { + fromRawValue(context, tmp_fontFamily->second, result.fontFamily); + } + auto tmp_fontWeight = map.find("fontWeight"); + if (tmp_fontWeight != map.end()) { + fromRawValue(context, tmp_fontWeight->second, result.fontWeight); + } + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } + auto tmp_marginTop = map.find("marginTop"); + if (tmp_marginTop != map.end()) { + fromRawValue(context, tmp_marginTop->second, result.marginTop); + } + auto tmp_marginBottom = map.find("marginBottom"); + if (tmp_marginBottom != map.end()) { + fromRawValue(context, tmp_marginBottom->second, result.marginBottom); + } + auto tmp_lineHeight = map.find("lineHeight"); + if (tmp_lineHeight != map.end()) { + fromRawValue(context, tmp_lineHeight->second, result.lineHeight); + } + auto tmp_backgroundColor = map.find("backgroundColor"); + if (tmp_backgroundColor != map.end()) { + fromRawValue(context, tmp_backgroundColor->second, result.backgroundColor); + } + auto tmp_borderColor = map.find("borderColor"); + if (tmp_borderColor != map.end()) { + fromRawValue(context, tmp_borderColor->second, result.borderColor); + } + auto tmp_borderRadius = map.find("borderRadius"); + if (tmp_borderRadius != map.end()) { + fromRawValue(context, tmp_borderRadius->second, result.borderRadius); + } + auto tmp_borderWidth = map.find("borderWidth"); + if (tmp_borderWidth != map.end()) { + fromRawValue(context, tmp_borderWidth->second, result.borderWidth); + } + auto tmp_padding = map.find("padding"); + if (tmp_padding != map.end()) { + fromRawValue(context, tmp_padding->second, result.padding); + } +} + +static inline std::string toString(const EnrichedMarkdownMarkdownStyleCodeBlockStruct &value) { + return "[Object EnrichedMarkdownMarkdownStyleCodeBlockStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownMarkdownStyleCodeBlockStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownMarkdownStyleLinkStruct { + std::string fontFamily{}; + SharedColor color{}; + bool underline{false}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownMarkdownStyleLinkStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["fontFamily"] = fontFamily; + result["color"] = ::facebook::react::toDynamic(color); + result["underline"] = underline; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownMarkdownStyleLinkStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_fontFamily = map.find("fontFamily"); + if (tmp_fontFamily != map.end()) { + fromRawValue(context, tmp_fontFamily->second, result.fontFamily); + } + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } + auto tmp_underline = map.find("underline"); + if (tmp_underline != map.end()) { + fromRawValue(context, tmp_underline->second, result.underline); + } +} + +static inline std::string toString(const EnrichedMarkdownMarkdownStyleLinkStruct &value) { + return "[Object EnrichedMarkdownMarkdownStyleLinkStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownMarkdownStyleLinkStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownMarkdownStyleStrongStruct { + std::string fontFamily{}; + std::string fontWeight{}; + SharedColor color{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownMarkdownStyleStrongStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["fontFamily"] = fontFamily; + result["fontWeight"] = fontWeight; + result["color"] = ::facebook::react::toDynamic(color); + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownMarkdownStyleStrongStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_fontFamily = map.find("fontFamily"); + if (tmp_fontFamily != map.end()) { + fromRawValue(context, tmp_fontFamily->second, result.fontFamily); + } + auto tmp_fontWeight = map.find("fontWeight"); + if (tmp_fontWeight != map.end()) { + fromRawValue(context, tmp_fontWeight->second, result.fontWeight); + } + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } +} + +static inline std::string toString(const EnrichedMarkdownMarkdownStyleStrongStruct &value) { + return "[Object EnrichedMarkdownMarkdownStyleStrongStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownMarkdownStyleStrongStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownMarkdownStyleEmStruct { + std::string fontFamily{}; + std::string fontStyle{}; + SharedColor color{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownMarkdownStyleEmStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["fontFamily"] = fontFamily; + result["fontStyle"] = fontStyle; + result["color"] = ::facebook::react::toDynamic(color); + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownMarkdownStyleEmStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_fontFamily = map.find("fontFamily"); + if (tmp_fontFamily != map.end()) { + fromRawValue(context, tmp_fontFamily->second, result.fontFamily); + } + auto tmp_fontStyle = map.find("fontStyle"); + if (tmp_fontStyle != map.end()) { + fromRawValue(context, tmp_fontStyle->second, result.fontStyle); + } + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } +} + +static inline std::string toString(const EnrichedMarkdownMarkdownStyleEmStruct &value) { + return "[Object EnrichedMarkdownMarkdownStyleEmStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownMarkdownStyleEmStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownMarkdownStyleStrikethroughStruct { + SharedColor color{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownMarkdownStyleStrikethroughStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["color"] = ::facebook::react::toDynamic(color); + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownMarkdownStyleStrikethroughStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } +} + +static inline std::string toString(const EnrichedMarkdownMarkdownStyleStrikethroughStruct &value) { + return "[Object EnrichedMarkdownMarkdownStyleStrikethroughStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownMarkdownStyleStrikethroughStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownMarkdownStyleUnderlineStruct { + SharedColor color{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownMarkdownStyleUnderlineStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["color"] = ::facebook::react::toDynamic(color); + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownMarkdownStyleUnderlineStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } +} + +static inline std::string toString(const EnrichedMarkdownMarkdownStyleUnderlineStruct &value) { + return "[Object EnrichedMarkdownMarkdownStyleUnderlineStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownMarkdownStyleUnderlineStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownMarkdownStyleCodeStruct { + std::string fontFamily{}; + Float fontSize{0.0}; + SharedColor color{}; + SharedColor backgroundColor{}; + SharedColor borderColor{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownMarkdownStyleCodeStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["fontFamily"] = fontFamily; + result["fontSize"] = fontSize; + result["color"] = ::facebook::react::toDynamic(color); + result["backgroundColor"] = ::facebook::react::toDynamic(backgroundColor); + result["borderColor"] = ::facebook::react::toDynamic(borderColor); + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownMarkdownStyleCodeStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_fontFamily = map.find("fontFamily"); + if (tmp_fontFamily != map.end()) { + fromRawValue(context, tmp_fontFamily->second, result.fontFamily); + } + auto tmp_fontSize = map.find("fontSize"); + if (tmp_fontSize != map.end()) { + fromRawValue(context, tmp_fontSize->second, result.fontSize); + } + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } + auto tmp_backgroundColor = map.find("backgroundColor"); + if (tmp_backgroundColor != map.end()) { + fromRawValue(context, tmp_backgroundColor->second, result.backgroundColor); + } + auto tmp_borderColor = map.find("borderColor"); + if (tmp_borderColor != map.end()) { + fromRawValue(context, tmp_borderColor->second, result.borderColor); + } +} + +static inline std::string toString(const EnrichedMarkdownMarkdownStyleCodeStruct &value) { + return "[Object EnrichedMarkdownMarkdownStyleCodeStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownMarkdownStyleCodeStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownMarkdownStyleImageStruct { + Float height{0.0}; + Float borderRadius{0.0}; + Float marginTop{0.0}; + Float marginBottom{0.0}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownMarkdownStyleImageStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["height"] = height; + result["borderRadius"] = borderRadius; + result["marginTop"] = marginTop; + result["marginBottom"] = marginBottom; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownMarkdownStyleImageStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_height = map.find("height"); + if (tmp_height != map.end()) { + fromRawValue(context, tmp_height->second, result.height); + } + auto tmp_borderRadius = map.find("borderRadius"); + if (tmp_borderRadius != map.end()) { + fromRawValue(context, tmp_borderRadius->second, result.borderRadius); + } + auto tmp_marginTop = map.find("marginTop"); + if (tmp_marginTop != map.end()) { + fromRawValue(context, tmp_marginTop->second, result.marginTop); + } + auto tmp_marginBottom = map.find("marginBottom"); + if (tmp_marginBottom != map.end()) { + fromRawValue(context, tmp_marginBottom->second, result.marginBottom); + } +} + +static inline std::string toString(const EnrichedMarkdownMarkdownStyleImageStruct &value) { + return "[Object EnrichedMarkdownMarkdownStyleImageStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownMarkdownStyleImageStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownMarkdownStyleInlineImageStruct { + Float size{0.0}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownMarkdownStyleInlineImageStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["size"] = size; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownMarkdownStyleInlineImageStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_size = map.find("size"); + if (tmp_size != map.end()) { + fromRawValue(context, tmp_size->second, result.size); + } +} + +static inline std::string toString(const EnrichedMarkdownMarkdownStyleInlineImageStruct &value) { + return "[Object EnrichedMarkdownMarkdownStyleInlineImageStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownMarkdownStyleInlineImageStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownMarkdownStyleThematicBreakStruct { + SharedColor color{}; + Float height{0.0}; + Float marginTop{0.0}; + Float marginBottom{0.0}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownMarkdownStyleThematicBreakStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["color"] = ::facebook::react::toDynamic(color); + result["height"] = height; + result["marginTop"] = marginTop; + result["marginBottom"] = marginBottom; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownMarkdownStyleThematicBreakStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } + auto tmp_height = map.find("height"); + if (tmp_height != map.end()) { + fromRawValue(context, tmp_height->second, result.height); + } + auto tmp_marginTop = map.find("marginTop"); + if (tmp_marginTop != map.end()) { + fromRawValue(context, tmp_marginTop->second, result.marginTop); + } + auto tmp_marginBottom = map.find("marginBottom"); + if (tmp_marginBottom != map.end()) { + fromRawValue(context, tmp_marginBottom->second, result.marginBottom); + } +} + +static inline std::string toString(const EnrichedMarkdownMarkdownStyleThematicBreakStruct &value) { + return "[Object EnrichedMarkdownMarkdownStyleThematicBreakStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownMarkdownStyleThematicBreakStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownMarkdownStyleTableStruct { + Float fontSize{0.0}; + std::string fontFamily{}; + std::string fontWeight{}; + SharedColor color{}; + Float marginTop{0.0}; + Float marginBottom{0.0}; + Float lineHeight{0.0}; + std::string headerFontFamily{}; + SharedColor headerBackgroundColor{}; + SharedColor headerTextColor{}; + SharedColor rowEvenBackgroundColor{}; + SharedColor rowOddBackgroundColor{}; + SharedColor borderColor{}; + Float borderWidth{0.0}; + Float borderRadius{0.0}; + Float cellPaddingHorizontal{0.0}; + Float cellPaddingVertical{0.0}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownMarkdownStyleTableStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["fontSize"] = fontSize; + result["fontFamily"] = fontFamily; + result["fontWeight"] = fontWeight; + result["color"] = ::facebook::react::toDynamic(color); + result["marginTop"] = marginTop; + result["marginBottom"] = marginBottom; + result["lineHeight"] = lineHeight; + result["headerFontFamily"] = headerFontFamily; + result["headerBackgroundColor"] = ::facebook::react::toDynamic(headerBackgroundColor); + result["headerTextColor"] = ::facebook::react::toDynamic(headerTextColor); + result["rowEvenBackgroundColor"] = ::facebook::react::toDynamic(rowEvenBackgroundColor); + result["rowOddBackgroundColor"] = ::facebook::react::toDynamic(rowOddBackgroundColor); + result["borderColor"] = ::facebook::react::toDynamic(borderColor); + result["borderWidth"] = borderWidth; + result["borderRadius"] = borderRadius; + result["cellPaddingHorizontal"] = cellPaddingHorizontal; + result["cellPaddingVertical"] = cellPaddingVertical; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownMarkdownStyleTableStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_fontSize = map.find("fontSize"); + if (tmp_fontSize != map.end()) { + fromRawValue(context, tmp_fontSize->second, result.fontSize); + } + auto tmp_fontFamily = map.find("fontFamily"); + if (tmp_fontFamily != map.end()) { + fromRawValue(context, tmp_fontFamily->second, result.fontFamily); + } + auto tmp_fontWeight = map.find("fontWeight"); + if (tmp_fontWeight != map.end()) { + fromRawValue(context, tmp_fontWeight->second, result.fontWeight); + } + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } + auto tmp_marginTop = map.find("marginTop"); + if (tmp_marginTop != map.end()) { + fromRawValue(context, tmp_marginTop->second, result.marginTop); + } + auto tmp_marginBottom = map.find("marginBottom"); + if (tmp_marginBottom != map.end()) { + fromRawValue(context, tmp_marginBottom->second, result.marginBottom); + } + auto tmp_lineHeight = map.find("lineHeight"); + if (tmp_lineHeight != map.end()) { + fromRawValue(context, tmp_lineHeight->second, result.lineHeight); + } + auto tmp_headerFontFamily = map.find("headerFontFamily"); + if (tmp_headerFontFamily != map.end()) { + fromRawValue(context, tmp_headerFontFamily->second, result.headerFontFamily); + } + auto tmp_headerBackgroundColor = map.find("headerBackgroundColor"); + if (tmp_headerBackgroundColor != map.end()) { + fromRawValue(context, tmp_headerBackgroundColor->second, result.headerBackgroundColor); + } + auto tmp_headerTextColor = map.find("headerTextColor"); + if (tmp_headerTextColor != map.end()) { + fromRawValue(context, tmp_headerTextColor->second, result.headerTextColor); + } + auto tmp_rowEvenBackgroundColor = map.find("rowEvenBackgroundColor"); + if (tmp_rowEvenBackgroundColor != map.end()) { + fromRawValue(context, tmp_rowEvenBackgroundColor->second, result.rowEvenBackgroundColor); + } + auto tmp_rowOddBackgroundColor = map.find("rowOddBackgroundColor"); + if (tmp_rowOddBackgroundColor != map.end()) { + fromRawValue(context, tmp_rowOddBackgroundColor->second, result.rowOddBackgroundColor); + } + auto tmp_borderColor = map.find("borderColor"); + if (tmp_borderColor != map.end()) { + fromRawValue(context, tmp_borderColor->second, result.borderColor); + } + auto tmp_borderWidth = map.find("borderWidth"); + if (tmp_borderWidth != map.end()) { + fromRawValue(context, tmp_borderWidth->second, result.borderWidth); + } + auto tmp_borderRadius = map.find("borderRadius"); + if (tmp_borderRadius != map.end()) { + fromRawValue(context, tmp_borderRadius->second, result.borderRadius); + } + auto tmp_cellPaddingHorizontal = map.find("cellPaddingHorizontal"); + if (tmp_cellPaddingHorizontal != map.end()) { + fromRawValue(context, tmp_cellPaddingHorizontal->second, result.cellPaddingHorizontal); + } + auto tmp_cellPaddingVertical = map.find("cellPaddingVertical"); + if (tmp_cellPaddingVertical != map.end()) { + fromRawValue(context, tmp_cellPaddingVertical->second, result.cellPaddingVertical); + } +} + +static inline std::string toString(const EnrichedMarkdownMarkdownStyleTableStruct &value) { + return "[Object EnrichedMarkdownMarkdownStyleTableStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownMarkdownStyleTableStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownMarkdownStyleTaskListStruct { + SharedColor checkedColor{}; + SharedColor borderColor{}; + Float checkboxSize{0.0}; + Float checkboxBorderRadius{0.0}; + SharedColor checkmarkColor{}; + SharedColor checkedTextColor{}; + bool checkedStrikethrough{false}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownMarkdownStyleTaskListStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["checkedColor"] = ::facebook::react::toDynamic(checkedColor); + result["borderColor"] = ::facebook::react::toDynamic(borderColor); + result["checkboxSize"] = checkboxSize; + result["checkboxBorderRadius"] = checkboxBorderRadius; + result["checkmarkColor"] = ::facebook::react::toDynamic(checkmarkColor); + result["checkedTextColor"] = ::facebook::react::toDynamic(checkedTextColor); + result["checkedStrikethrough"] = checkedStrikethrough; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownMarkdownStyleTaskListStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_checkedColor = map.find("checkedColor"); + if (tmp_checkedColor != map.end()) { + fromRawValue(context, tmp_checkedColor->second, result.checkedColor); + } + auto tmp_borderColor = map.find("borderColor"); + if (tmp_borderColor != map.end()) { + fromRawValue(context, tmp_borderColor->second, result.borderColor); + } + auto tmp_checkboxSize = map.find("checkboxSize"); + if (tmp_checkboxSize != map.end()) { + fromRawValue(context, tmp_checkboxSize->second, result.checkboxSize); + } + auto tmp_checkboxBorderRadius = map.find("checkboxBorderRadius"); + if (tmp_checkboxBorderRadius != map.end()) { + fromRawValue(context, tmp_checkboxBorderRadius->second, result.checkboxBorderRadius); + } + auto tmp_checkmarkColor = map.find("checkmarkColor"); + if (tmp_checkmarkColor != map.end()) { + fromRawValue(context, tmp_checkmarkColor->second, result.checkmarkColor); + } + auto tmp_checkedTextColor = map.find("checkedTextColor"); + if (tmp_checkedTextColor != map.end()) { + fromRawValue(context, tmp_checkedTextColor->second, result.checkedTextColor); + } + auto tmp_checkedStrikethrough = map.find("checkedStrikethrough"); + if (tmp_checkedStrikethrough != map.end()) { + fromRawValue(context, tmp_checkedStrikethrough->second, result.checkedStrikethrough); + } +} + +static inline std::string toString(const EnrichedMarkdownMarkdownStyleTaskListStruct &value) { + return "[Object EnrichedMarkdownMarkdownStyleTaskListStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownMarkdownStyleTaskListStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownMarkdownStyleMathStruct { + Float fontSize{0.0}; + SharedColor color{}; + SharedColor backgroundColor{}; + Float padding{0.0}; + Float marginTop{0.0}; + Float marginBottom{0.0}; + std::string textAlign{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownMarkdownStyleMathStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["fontSize"] = fontSize; + result["color"] = ::facebook::react::toDynamic(color); + result["backgroundColor"] = ::facebook::react::toDynamic(backgroundColor); + result["padding"] = padding; + result["marginTop"] = marginTop; + result["marginBottom"] = marginBottom; + result["textAlign"] = textAlign; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownMarkdownStyleMathStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_fontSize = map.find("fontSize"); + if (tmp_fontSize != map.end()) { + fromRawValue(context, tmp_fontSize->second, result.fontSize); + } + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } + auto tmp_backgroundColor = map.find("backgroundColor"); + if (tmp_backgroundColor != map.end()) { + fromRawValue(context, tmp_backgroundColor->second, result.backgroundColor); + } + auto tmp_padding = map.find("padding"); + if (tmp_padding != map.end()) { + fromRawValue(context, tmp_padding->second, result.padding); + } + auto tmp_marginTop = map.find("marginTop"); + if (tmp_marginTop != map.end()) { + fromRawValue(context, tmp_marginTop->second, result.marginTop); + } + auto tmp_marginBottom = map.find("marginBottom"); + if (tmp_marginBottom != map.end()) { + fromRawValue(context, tmp_marginBottom->second, result.marginBottom); + } + auto tmp_textAlign = map.find("textAlign"); + if (tmp_textAlign != map.end()) { + fromRawValue(context, tmp_textAlign->second, result.textAlign); + } +} + +static inline std::string toString(const EnrichedMarkdownMarkdownStyleMathStruct &value) { + return "[Object EnrichedMarkdownMarkdownStyleMathStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownMarkdownStyleMathStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownMarkdownStyleInlineMathStruct { + SharedColor color{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownMarkdownStyleInlineMathStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["color"] = ::facebook::react::toDynamic(color); + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownMarkdownStyleInlineMathStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } +} + +static inline std::string toString(const EnrichedMarkdownMarkdownStyleInlineMathStruct &value) { + return "[Object EnrichedMarkdownMarkdownStyleInlineMathStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownMarkdownStyleInlineMathStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownMarkdownStyleSpoilerParticlesStruct { + Float density{0.0}; + Float speed{0.0}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownMarkdownStyleSpoilerParticlesStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["density"] = density; + result["speed"] = speed; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownMarkdownStyleSpoilerParticlesStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_density = map.find("density"); + if (tmp_density != map.end()) { + fromRawValue(context, tmp_density->second, result.density); + } + auto tmp_speed = map.find("speed"); + if (tmp_speed != map.end()) { + fromRawValue(context, tmp_speed->second, result.speed); + } +} + +static inline std::string toString(const EnrichedMarkdownMarkdownStyleSpoilerParticlesStruct &value) { + return "[Object EnrichedMarkdownMarkdownStyleSpoilerParticlesStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownMarkdownStyleSpoilerParticlesStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownMarkdownStyleSpoilerSolidStruct { + Float borderRadius{0.0}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownMarkdownStyleSpoilerSolidStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["borderRadius"] = borderRadius; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownMarkdownStyleSpoilerSolidStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_borderRadius = map.find("borderRadius"); + if (tmp_borderRadius != map.end()) { + fromRawValue(context, tmp_borderRadius->second, result.borderRadius); + } +} + +static inline std::string toString(const EnrichedMarkdownMarkdownStyleSpoilerSolidStruct &value) { + return "[Object EnrichedMarkdownMarkdownStyleSpoilerSolidStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownMarkdownStyleSpoilerSolidStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownMarkdownStyleSpoilerStruct { + SharedColor color{}; + EnrichedMarkdownMarkdownStyleSpoilerParticlesStruct particles{}; + EnrichedMarkdownMarkdownStyleSpoilerSolidStruct solid{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownMarkdownStyleSpoilerStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["color"] = ::facebook::react::toDynamic(color); + result["particles"] = ::facebook::react::toDynamic(particles); + result["solid"] = ::facebook::react::toDynamic(solid); + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownMarkdownStyleSpoilerStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } + auto tmp_particles = map.find("particles"); + if (tmp_particles != map.end()) { + fromRawValue(context, tmp_particles->second, result.particles); + } + auto tmp_solid = map.find("solid"); + if (tmp_solid != map.end()) { + fromRawValue(context, tmp_solid->second, result.solid); + } +} + +static inline std::string toString(const EnrichedMarkdownMarkdownStyleSpoilerStruct &value) { + return "[Object EnrichedMarkdownMarkdownStyleSpoilerStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownMarkdownStyleSpoilerStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownMarkdownStyleMentionStruct { + SharedColor color{}; + SharedColor backgroundColor{}; + SharedColor borderColor{}; + Float borderWidth{0.0}; + Float borderRadius{0.0}; + Float paddingHorizontal{0.0}; + Float paddingVertical{0.0}; + std::string fontFamily{}; + std::string fontWeight{}; + Float fontSize{0.0}; + Float pressedOpacity{0.0}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownMarkdownStyleMentionStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["color"] = ::facebook::react::toDynamic(color); + result["backgroundColor"] = ::facebook::react::toDynamic(backgroundColor); + result["borderColor"] = ::facebook::react::toDynamic(borderColor); + result["borderWidth"] = borderWidth; + result["borderRadius"] = borderRadius; + result["paddingHorizontal"] = paddingHorizontal; + result["paddingVertical"] = paddingVertical; + result["fontFamily"] = fontFamily; + result["fontWeight"] = fontWeight; + result["fontSize"] = fontSize; + result["pressedOpacity"] = pressedOpacity; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownMarkdownStyleMentionStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } + auto tmp_backgroundColor = map.find("backgroundColor"); + if (tmp_backgroundColor != map.end()) { + fromRawValue(context, tmp_backgroundColor->second, result.backgroundColor); + } + auto tmp_borderColor = map.find("borderColor"); + if (tmp_borderColor != map.end()) { + fromRawValue(context, tmp_borderColor->second, result.borderColor); + } + auto tmp_borderWidth = map.find("borderWidth"); + if (tmp_borderWidth != map.end()) { + fromRawValue(context, tmp_borderWidth->second, result.borderWidth); + } + auto tmp_borderRadius = map.find("borderRadius"); + if (tmp_borderRadius != map.end()) { + fromRawValue(context, tmp_borderRadius->second, result.borderRadius); + } + auto tmp_paddingHorizontal = map.find("paddingHorizontal"); + if (tmp_paddingHorizontal != map.end()) { + fromRawValue(context, tmp_paddingHorizontal->second, result.paddingHorizontal); + } + auto tmp_paddingVertical = map.find("paddingVertical"); + if (tmp_paddingVertical != map.end()) { + fromRawValue(context, tmp_paddingVertical->second, result.paddingVertical); + } + auto tmp_fontFamily = map.find("fontFamily"); + if (tmp_fontFamily != map.end()) { + fromRawValue(context, tmp_fontFamily->second, result.fontFamily); + } + auto tmp_fontWeight = map.find("fontWeight"); + if (tmp_fontWeight != map.end()) { + fromRawValue(context, tmp_fontWeight->second, result.fontWeight); + } + auto tmp_fontSize = map.find("fontSize"); + if (tmp_fontSize != map.end()) { + fromRawValue(context, tmp_fontSize->second, result.fontSize); + } + auto tmp_pressedOpacity = map.find("pressedOpacity"); + if (tmp_pressedOpacity != map.end()) { + fromRawValue(context, tmp_pressedOpacity->second, result.pressedOpacity); + } +} + +static inline std::string toString(const EnrichedMarkdownMarkdownStyleMentionStruct &value) { + return "[Object EnrichedMarkdownMarkdownStyleMentionStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownMarkdownStyleMentionStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownMarkdownStyleCitationStruct { + SharedColor color{}; + Float fontSizeMultiplier{0.0}; + Float baselineOffsetPx{0.0}; + std::string fontWeight{}; + bool underline{false}; + SharedColor backgroundColor{}; + Float paddingHorizontal{0.0}; + Float paddingVertical{0.0}; + SharedColor borderColor{}; + Float borderWidth{0.0}; + Float borderRadius{0.0}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownMarkdownStyleCitationStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["color"] = ::facebook::react::toDynamic(color); + result["fontSizeMultiplier"] = fontSizeMultiplier; + result["baselineOffsetPx"] = baselineOffsetPx; + result["fontWeight"] = fontWeight; + result["underline"] = underline; + result["backgroundColor"] = ::facebook::react::toDynamic(backgroundColor); + result["paddingHorizontal"] = paddingHorizontal; + result["paddingVertical"] = paddingVertical; + result["borderColor"] = ::facebook::react::toDynamic(borderColor); + result["borderWidth"] = borderWidth; + result["borderRadius"] = borderRadius; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownMarkdownStyleCitationStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } + auto tmp_fontSizeMultiplier = map.find("fontSizeMultiplier"); + if (tmp_fontSizeMultiplier != map.end()) { + fromRawValue(context, tmp_fontSizeMultiplier->second, result.fontSizeMultiplier); + } + auto tmp_baselineOffsetPx = map.find("baselineOffsetPx"); + if (tmp_baselineOffsetPx != map.end()) { + fromRawValue(context, tmp_baselineOffsetPx->second, result.baselineOffsetPx); + } + auto tmp_fontWeight = map.find("fontWeight"); + if (tmp_fontWeight != map.end()) { + fromRawValue(context, tmp_fontWeight->second, result.fontWeight); + } + auto tmp_underline = map.find("underline"); + if (tmp_underline != map.end()) { + fromRawValue(context, tmp_underline->second, result.underline); + } + auto tmp_backgroundColor = map.find("backgroundColor"); + if (tmp_backgroundColor != map.end()) { + fromRawValue(context, tmp_backgroundColor->second, result.backgroundColor); + } + auto tmp_paddingHorizontal = map.find("paddingHorizontal"); + if (tmp_paddingHorizontal != map.end()) { + fromRawValue(context, tmp_paddingHorizontal->second, result.paddingHorizontal); + } + auto tmp_paddingVertical = map.find("paddingVertical"); + if (tmp_paddingVertical != map.end()) { + fromRawValue(context, tmp_paddingVertical->second, result.paddingVertical); + } + auto tmp_borderColor = map.find("borderColor"); + if (tmp_borderColor != map.end()) { + fromRawValue(context, tmp_borderColor->second, result.borderColor); + } + auto tmp_borderWidth = map.find("borderWidth"); + if (tmp_borderWidth != map.end()) { + fromRawValue(context, tmp_borderWidth->second, result.borderWidth); + } + auto tmp_borderRadius = map.find("borderRadius"); + if (tmp_borderRadius != map.end()) { + fromRawValue(context, tmp_borderRadius->second, result.borderRadius); + } +} + +static inline std::string toString(const EnrichedMarkdownMarkdownStyleCitationStruct &value) { + return "[Object EnrichedMarkdownMarkdownStyleCitationStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownMarkdownStyleCitationStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownMarkdownStyleStruct { + EnrichedMarkdownMarkdownStyleParagraphStruct paragraph{}; + EnrichedMarkdownMarkdownStyleH1Struct h1{}; + EnrichedMarkdownMarkdownStyleH2Struct h2{}; + EnrichedMarkdownMarkdownStyleH3Struct h3{}; + EnrichedMarkdownMarkdownStyleH4Struct h4{}; + EnrichedMarkdownMarkdownStyleH5Struct h5{}; + EnrichedMarkdownMarkdownStyleH6Struct h6{}; + EnrichedMarkdownMarkdownStyleBlockquoteStruct blockquote{}; + EnrichedMarkdownMarkdownStyleListStruct list{}; + EnrichedMarkdownMarkdownStyleCodeBlockStruct codeBlock{}; + EnrichedMarkdownMarkdownStyleLinkStruct link{}; + EnrichedMarkdownMarkdownStyleStrongStruct strong{}; + EnrichedMarkdownMarkdownStyleEmStruct em{}; + EnrichedMarkdownMarkdownStyleStrikethroughStruct strikethrough{}; + EnrichedMarkdownMarkdownStyleUnderlineStruct underline{}; + EnrichedMarkdownMarkdownStyleCodeStruct code{}; + EnrichedMarkdownMarkdownStyleImageStruct image{}; + EnrichedMarkdownMarkdownStyleInlineImageStruct inlineImage{}; + EnrichedMarkdownMarkdownStyleThematicBreakStruct thematicBreak{}; + EnrichedMarkdownMarkdownStyleTableStruct table{}; + EnrichedMarkdownMarkdownStyleTaskListStruct taskList{}; + EnrichedMarkdownMarkdownStyleMathStruct math{}; + EnrichedMarkdownMarkdownStyleInlineMathStruct inlineMath{}; + EnrichedMarkdownMarkdownStyleSpoilerStruct spoiler{}; + EnrichedMarkdownMarkdownStyleMentionStruct mention{}; + EnrichedMarkdownMarkdownStyleCitationStruct citation{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownMarkdownStyleStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["paragraph"] = ::facebook::react::toDynamic(paragraph); + result["h1"] = ::facebook::react::toDynamic(h1); + result["h2"] = ::facebook::react::toDynamic(h2); + result["h3"] = ::facebook::react::toDynamic(h3); + result["h4"] = ::facebook::react::toDynamic(h4); + result["h5"] = ::facebook::react::toDynamic(h5); + result["h6"] = ::facebook::react::toDynamic(h6); + result["blockquote"] = ::facebook::react::toDynamic(blockquote); + result["list"] = ::facebook::react::toDynamic(list); + result["codeBlock"] = ::facebook::react::toDynamic(codeBlock); + result["link"] = ::facebook::react::toDynamic(link); + result["strong"] = ::facebook::react::toDynamic(strong); + result["em"] = ::facebook::react::toDynamic(em); + result["strikethrough"] = ::facebook::react::toDynamic(strikethrough); + result["underline"] = ::facebook::react::toDynamic(underline); + result["code"] = ::facebook::react::toDynamic(code); + result["image"] = ::facebook::react::toDynamic(image); + result["inlineImage"] = ::facebook::react::toDynamic(inlineImage); + result["thematicBreak"] = ::facebook::react::toDynamic(thematicBreak); + result["table"] = ::facebook::react::toDynamic(table); + result["taskList"] = ::facebook::react::toDynamic(taskList); + result["math"] = ::facebook::react::toDynamic(math); + result["inlineMath"] = ::facebook::react::toDynamic(inlineMath); + result["spoiler"] = ::facebook::react::toDynamic(spoiler); + result["mention"] = ::facebook::react::toDynamic(mention); + result["citation"] = ::facebook::react::toDynamic(citation); + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownMarkdownStyleStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_paragraph = map.find("paragraph"); + if (tmp_paragraph != map.end()) { + fromRawValue(context, tmp_paragraph->second, result.paragraph); + } + auto tmp_h1 = map.find("h1"); + if (tmp_h1 != map.end()) { + fromRawValue(context, tmp_h1->second, result.h1); + } + auto tmp_h2 = map.find("h2"); + if (tmp_h2 != map.end()) { + fromRawValue(context, tmp_h2->second, result.h2); + } + auto tmp_h3 = map.find("h3"); + if (tmp_h3 != map.end()) { + fromRawValue(context, tmp_h3->second, result.h3); + } + auto tmp_h4 = map.find("h4"); + if (tmp_h4 != map.end()) { + fromRawValue(context, tmp_h4->second, result.h4); + } + auto tmp_h5 = map.find("h5"); + if (tmp_h5 != map.end()) { + fromRawValue(context, tmp_h5->second, result.h5); + } + auto tmp_h6 = map.find("h6"); + if (tmp_h6 != map.end()) { + fromRawValue(context, tmp_h6->second, result.h6); + } + auto tmp_blockquote = map.find("blockquote"); + if (tmp_blockquote != map.end()) { + fromRawValue(context, tmp_blockquote->second, result.blockquote); + } + auto tmp_list = map.find("list"); + if (tmp_list != map.end()) { + fromRawValue(context, tmp_list->second, result.list); + } + auto tmp_codeBlock = map.find("codeBlock"); + if (tmp_codeBlock != map.end()) { + fromRawValue(context, tmp_codeBlock->second, result.codeBlock); + } + auto tmp_link = map.find("link"); + if (tmp_link != map.end()) { + fromRawValue(context, tmp_link->second, result.link); + } + auto tmp_strong = map.find("strong"); + if (tmp_strong != map.end()) { + fromRawValue(context, tmp_strong->second, result.strong); + } + auto tmp_em = map.find("em"); + if (tmp_em != map.end()) { + fromRawValue(context, tmp_em->second, result.em); + } + auto tmp_strikethrough = map.find("strikethrough"); + if (tmp_strikethrough != map.end()) { + fromRawValue(context, tmp_strikethrough->second, result.strikethrough); + } + auto tmp_underline = map.find("underline"); + if (tmp_underline != map.end()) { + fromRawValue(context, tmp_underline->second, result.underline); + } + auto tmp_code = map.find("code"); + if (tmp_code != map.end()) { + fromRawValue(context, tmp_code->second, result.code); + } + auto tmp_image = map.find("image"); + if (tmp_image != map.end()) { + fromRawValue(context, tmp_image->second, result.image); + } + auto tmp_inlineImage = map.find("inlineImage"); + if (tmp_inlineImage != map.end()) { + fromRawValue(context, tmp_inlineImage->second, result.inlineImage); + } + auto tmp_thematicBreak = map.find("thematicBreak"); + if (tmp_thematicBreak != map.end()) { + fromRawValue(context, tmp_thematicBreak->second, result.thematicBreak); + } + auto tmp_table = map.find("table"); + if (tmp_table != map.end()) { + fromRawValue(context, tmp_table->second, result.table); + } + auto tmp_taskList = map.find("taskList"); + if (tmp_taskList != map.end()) { + fromRawValue(context, tmp_taskList->second, result.taskList); + } + auto tmp_math = map.find("math"); + if (tmp_math != map.end()) { + fromRawValue(context, tmp_math->second, result.math); + } + auto tmp_inlineMath = map.find("inlineMath"); + if (tmp_inlineMath != map.end()) { + fromRawValue(context, tmp_inlineMath->second, result.inlineMath); + } + auto tmp_spoiler = map.find("spoiler"); + if (tmp_spoiler != map.end()) { + fromRawValue(context, tmp_spoiler->second, result.spoiler); + } + auto tmp_mention = map.find("mention"); + if (tmp_mention != map.end()) { + fromRawValue(context, tmp_mention->second, result.mention); + } + auto tmp_citation = map.find("citation"); + if (tmp_citation != map.end()) { + fromRawValue(context, tmp_citation->second, result.citation); + } +} + +static inline std::string toString(const EnrichedMarkdownMarkdownStyleStruct &value) { + return "[Object EnrichedMarkdownMarkdownStyleStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownMarkdownStyleStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownMd4cFlagsStruct { + bool underline{false}; + bool latexMath{false}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownMd4cFlagsStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["underline"] = underline; + result["latexMath"] = latexMath; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownMd4cFlagsStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_underline = map.find("underline"); + if (tmp_underline != map.end()) { + fromRawValue(context, tmp_underline->second, result.underline); + } + auto tmp_latexMath = map.find("latexMath"); + if (tmp_latexMath != map.end()) { + fromRawValue(context, tmp_latexMath->second, result.latexMath); + } +} + +static inline std::string toString(const EnrichedMarkdownMd4cFlagsStruct &value) { + return "[Object EnrichedMarkdownMd4cFlagsStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownMd4cFlagsStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownContextMenuItemsStruct { + std::string text{}; + std::string icon{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownContextMenuItemsStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["text"] = text; + result["icon"] = icon; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownContextMenuItemsStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_text = map.find("text"); + if (tmp_text != map.end()) { + fromRawValue(context, tmp_text->second, result.text); + } + auto tmp_icon = map.find("icon"); + if (tmp_icon != map.end()) { + fromRawValue(context, tmp_icon->second, result.icon); + } +} + +static inline std::string toString(const EnrichedMarkdownContextMenuItemsStruct &value) { + return "[Object EnrichedMarkdownContextMenuItemsStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownContextMenuItemsStruct &value) { + return value.toDynamic(); +} +#endif + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, std::vector &result) { + auto items = (std::vector)value; + for (const auto &item : items) { + EnrichedMarkdownContextMenuItemsStruct newItem; + fromRawValue(context, item, newItem); + result.emplace_back(newItem); + } +} + +class EnrichedMarkdownProps final : public ViewProps { + public: + EnrichedMarkdownProps() = default; + EnrichedMarkdownProps(const PropsParserContext& context, const EnrichedMarkdownProps &sourceProps, const RawProps &rawProps); + +#pragma mark - Props + + std::string markdown{}; + EnrichedMarkdownMarkdownStyleStruct markdownStyle{}; + bool enableLinkPreview{true}; + bool selectable{false}; + SharedColor selectionColor{}; + SharedColor selectionHandleColor{}; + EnrichedMarkdownMd4cFlagsStruct md4cFlags{}; + bool allowFontScaling{true}; + Float maxFontSizeMultiplier{0.0}; + bool allowTrailingMargin{false}; + bool streamingAnimation{false}; + std::string spoilerOverlay{std::string{"particles"}}; + std::vector contextMenuItems{}; + + #ifdef RN_SERIALIZABLE_STATE + ComponentName getDiffPropsImplementationTarget() const override; + + folly::dynamic getDiffProps(const Props* prevProps) const override; + #endif + + +}; + +struct EnrichedMarkdownTextInputMarkdownStyleStrongStruct { + SharedColor color{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownTextInputMarkdownStyleStrongStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["color"] = ::facebook::react::toDynamic(color); + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownTextInputMarkdownStyleStrongStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } +} + +static inline std::string toString(const EnrichedMarkdownTextInputMarkdownStyleStrongStruct &value) { + return "[Object EnrichedMarkdownTextInputMarkdownStyleStrongStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownTextInputMarkdownStyleStrongStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownTextInputMarkdownStyleEmStruct { + SharedColor color{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownTextInputMarkdownStyleEmStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["color"] = ::facebook::react::toDynamic(color); + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownTextInputMarkdownStyleEmStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } +} + +static inline std::string toString(const EnrichedMarkdownTextInputMarkdownStyleEmStruct &value) { + return "[Object EnrichedMarkdownTextInputMarkdownStyleEmStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownTextInputMarkdownStyleEmStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownTextInputMarkdownStyleLinkStruct { + SharedColor color{}; + bool underline{false}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownTextInputMarkdownStyleLinkStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["color"] = ::facebook::react::toDynamic(color); + result["underline"] = underline; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownTextInputMarkdownStyleLinkStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } + auto tmp_underline = map.find("underline"); + if (tmp_underline != map.end()) { + fromRawValue(context, tmp_underline->second, result.underline); + } +} + +static inline std::string toString(const EnrichedMarkdownTextInputMarkdownStyleLinkStruct &value) { + return "[Object EnrichedMarkdownTextInputMarkdownStyleLinkStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownTextInputMarkdownStyleLinkStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownTextInputMarkdownStyleSpoilerStruct { + SharedColor color{}; + SharedColor backgroundColor{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownTextInputMarkdownStyleSpoilerStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["color"] = ::facebook::react::toDynamic(color); + result["backgroundColor"] = ::facebook::react::toDynamic(backgroundColor); + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownTextInputMarkdownStyleSpoilerStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } + auto tmp_backgroundColor = map.find("backgroundColor"); + if (tmp_backgroundColor != map.end()) { + fromRawValue(context, tmp_backgroundColor->second, result.backgroundColor); + } +} + +static inline std::string toString(const EnrichedMarkdownTextInputMarkdownStyleSpoilerStruct &value) { + return "[Object EnrichedMarkdownTextInputMarkdownStyleSpoilerStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownTextInputMarkdownStyleSpoilerStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownTextInputMarkdownStyleStruct { + EnrichedMarkdownTextInputMarkdownStyleStrongStruct strong{}; + EnrichedMarkdownTextInputMarkdownStyleEmStruct em{}; + EnrichedMarkdownTextInputMarkdownStyleLinkStruct link{}; + EnrichedMarkdownTextInputMarkdownStyleSpoilerStruct spoiler{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownTextInputMarkdownStyleStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["strong"] = ::facebook::react::toDynamic(strong); + result["em"] = ::facebook::react::toDynamic(em); + result["link"] = ::facebook::react::toDynamic(link); + result["spoiler"] = ::facebook::react::toDynamic(spoiler); + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownTextInputMarkdownStyleStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_strong = map.find("strong"); + if (tmp_strong != map.end()) { + fromRawValue(context, tmp_strong->second, result.strong); + } + auto tmp_em = map.find("em"); + if (tmp_em != map.end()) { + fromRawValue(context, tmp_em->second, result.em); + } + auto tmp_link = map.find("link"); + if (tmp_link != map.end()) { + fromRawValue(context, tmp_link->second, result.link); + } + auto tmp_spoiler = map.find("spoiler"); + if (tmp_spoiler != map.end()) { + fromRawValue(context, tmp_spoiler->second, result.spoiler); + } +} + +static inline std::string toString(const EnrichedMarkdownTextInputMarkdownStyleStruct &value) { + return "[Object EnrichedMarkdownTextInputMarkdownStyleStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownTextInputMarkdownStyleStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownTextInputContextMenuItemsStruct { + std::string text{}; + std::string icon{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownTextInputContextMenuItemsStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["text"] = text; + result["icon"] = icon; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownTextInputContextMenuItemsStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_text = map.find("text"); + if (tmp_text != map.end()) { + fromRawValue(context, tmp_text->second, result.text); + } + auto tmp_icon = map.find("icon"); + if (tmp_icon != map.end()) { + fromRawValue(context, tmp_icon->second, result.icon); + } +} + +static inline std::string toString(const EnrichedMarkdownTextInputContextMenuItemsStruct &value) { + return "[Object EnrichedMarkdownTextInputContextMenuItemsStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownTextInputContextMenuItemsStruct &value) { + return value.toDynamic(); +} +#endif + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, std::vector &result) { + auto items = (std::vector)value; + for (const auto &item : items) { + EnrichedMarkdownTextInputContextMenuItemsStruct newItem; + fromRawValue(context, item, newItem); + result.emplace_back(newItem); + } +} + + +struct EnrichedMarkdownTextInputLinkRegexStruct { + std::string pattern{}; + bool caseInsensitive{false}; + bool dotAll{false}; + bool isDisabled{false}; + bool isDefault{false}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownTextInputLinkRegexStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["pattern"] = pattern; + result["caseInsensitive"] = caseInsensitive; + result["dotAll"] = dotAll; + result["isDisabled"] = isDisabled; + result["isDefault"] = isDefault; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownTextInputLinkRegexStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_pattern = map.find("pattern"); + if (tmp_pattern != map.end()) { + fromRawValue(context, tmp_pattern->second, result.pattern); + } + auto tmp_caseInsensitive = map.find("caseInsensitive"); + if (tmp_caseInsensitive != map.end()) { + fromRawValue(context, tmp_caseInsensitive->second, result.caseInsensitive); + } + auto tmp_dotAll = map.find("dotAll"); + if (tmp_dotAll != map.end()) { + fromRawValue(context, tmp_dotAll->second, result.dotAll); + } + auto tmp_isDisabled = map.find("isDisabled"); + if (tmp_isDisabled != map.end()) { + fromRawValue(context, tmp_isDisabled->second, result.isDisabled); + } + auto tmp_isDefault = map.find("isDefault"); + if (tmp_isDefault != map.end()) { + fromRawValue(context, tmp_isDefault->second, result.isDefault); + } +} + +static inline std::string toString(const EnrichedMarkdownTextInputLinkRegexStruct &value) { + return "[Object EnrichedMarkdownTextInputLinkRegexStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownTextInputLinkRegexStruct &value) { + return value.toDynamic(); +} +#endif +class EnrichedMarkdownTextInputProps final : public ViewProps { + public: + EnrichedMarkdownTextInputProps() = default; + EnrichedMarkdownTextInputProps(const PropsParserContext& context, const EnrichedMarkdownTextInputProps &sourceProps, const RawProps &rawProps); + +#pragma mark - Props + + std::string defaultValue{}; + std::string placeholder{}; + SharedColor placeholderTextColor{}; + bool editable{false}; + bool autoFocus{false}; + bool scrollEnabled{false}; + std::string autoCapitalize{}; + bool multiline{false}; + SharedColor cursorColor{}; + SharedColor selectionColor{}; + EnrichedMarkdownTextInputMarkdownStyleStruct markdownStyle{}; + SharedColor color{}; + Float fontSize{0.0}; + Float lineHeight{0.0}; + std::string fontFamily{}; + std::string fontWeight{}; + bool isOnChangeMarkdownSet{false}; + std::vector contextMenuItems{}; + EnrichedMarkdownTextInputLinkRegexStruct linkRegex{}; + + #ifdef RN_SERIALIZABLE_STATE + ComponentName getDiffPropsImplementationTarget() const override; + + folly::dynamic getDiffProps(const Props* prevProps) const override; + #endif + + +}; + +struct EnrichedMarkdownTextMarkdownStyleParagraphStruct { + Float fontSize{0.0}; + std::string fontFamily{}; + std::string fontWeight{}; + SharedColor color{}; + Float marginTop{0.0}; + Float marginBottom{0.0}; + Float lineHeight{0.0}; + std::string textAlign{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownTextMarkdownStyleParagraphStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["fontSize"] = fontSize; + result["fontFamily"] = fontFamily; + result["fontWeight"] = fontWeight; + result["color"] = ::facebook::react::toDynamic(color); + result["marginTop"] = marginTop; + result["marginBottom"] = marginBottom; + result["lineHeight"] = lineHeight; + result["textAlign"] = textAlign; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownTextMarkdownStyleParagraphStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_fontSize = map.find("fontSize"); + if (tmp_fontSize != map.end()) { + fromRawValue(context, tmp_fontSize->second, result.fontSize); + } + auto tmp_fontFamily = map.find("fontFamily"); + if (tmp_fontFamily != map.end()) { + fromRawValue(context, tmp_fontFamily->second, result.fontFamily); + } + auto tmp_fontWeight = map.find("fontWeight"); + if (tmp_fontWeight != map.end()) { + fromRawValue(context, tmp_fontWeight->second, result.fontWeight); + } + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } + auto tmp_marginTop = map.find("marginTop"); + if (tmp_marginTop != map.end()) { + fromRawValue(context, tmp_marginTop->second, result.marginTop); + } + auto tmp_marginBottom = map.find("marginBottom"); + if (tmp_marginBottom != map.end()) { + fromRawValue(context, tmp_marginBottom->second, result.marginBottom); + } + auto tmp_lineHeight = map.find("lineHeight"); + if (tmp_lineHeight != map.end()) { + fromRawValue(context, tmp_lineHeight->second, result.lineHeight); + } + auto tmp_textAlign = map.find("textAlign"); + if (tmp_textAlign != map.end()) { + fromRawValue(context, tmp_textAlign->second, result.textAlign); + } +} + +static inline std::string toString(const EnrichedMarkdownTextMarkdownStyleParagraphStruct &value) { + return "[Object EnrichedMarkdownTextMarkdownStyleParagraphStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownTextMarkdownStyleParagraphStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownTextMarkdownStyleH1Struct { + Float fontSize{0.0}; + std::string fontFamily{}; + std::string fontWeight{}; + SharedColor color{}; + Float marginTop{0.0}; + Float marginBottom{0.0}; + Float lineHeight{0.0}; + std::string textAlign{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownTextMarkdownStyleH1Struct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["fontSize"] = fontSize; + result["fontFamily"] = fontFamily; + result["fontWeight"] = fontWeight; + result["color"] = ::facebook::react::toDynamic(color); + result["marginTop"] = marginTop; + result["marginBottom"] = marginBottom; + result["lineHeight"] = lineHeight; + result["textAlign"] = textAlign; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownTextMarkdownStyleH1Struct &result) { + auto map = (std::unordered_map)value; + + auto tmp_fontSize = map.find("fontSize"); + if (tmp_fontSize != map.end()) { + fromRawValue(context, tmp_fontSize->second, result.fontSize); + } + auto tmp_fontFamily = map.find("fontFamily"); + if (tmp_fontFamily != map.end()) { + fromRawValue(context, tmp_fontFamily->second, result.fontFamily); + } + auto tmp_fontWeight = map.find("fontWeight"); + if (tmp_fontWeight != map.end()) { + fromRawValue(context, tmp_fontWeight->second, result.fontWeight); + } + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } + auto tmp_marginTop = map.find("marginTop"); + if (tmp_marginTop != map.end()) { + fromRawValue(context, tmp_marginTop->second, result.marginTop); + } + auto tmp_marginBottom = map.find("marginBottom"); + if (tmp_marginBottom != map.end()) { + fromRawValue(context, tmp_marginBottom->second, result.marginBottom); + } + auto tmp_lineHeight = map.find("lineHeight"); + if (tmp_lineHeight != map.end()) { + fromRawValue(context, tmp_lineHeight->second, result.lineHeight); + } + auto tmp_textAlign = map.find("textAlign"); + if (tmp_textAlign != map.end()) { + fromRawValue(context, tmp_textAlign->second, result.textAlign); + } +} + +static inline std::string toString(const EnrichedMarkdownTextMarkdownStyleH1Struct &value) { + return "[Object EnrichedMarkdownTextMarkdownStyleH1Struct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownTextMarkdownStyleH1Struct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownTextMarkdownStyleH2Struct { + Float fontSize{0.0}; + std::string fontFamily{}; + std::string fontWeight{}; + SharedColor color{}; + Float marginTop{0.0}; + Float marginBottom{0.0}; + Float lineHeight{0.0}; + std::string textAlign{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownTextMarkdownStyleH2Struct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["fontSize"] = fontSize; + result["fontFamily"] = fontFamily; + result["fontWeight"] = fontWeight; + result["color"] = ::facebook::react::toDynamic(color); + result["marginTop"] = marginTop; + result["marginBottom"] = marginBottom; + result["lineHeight"] = lineHeight; + result["textAlign"] = textAlign; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownTextMarkdownStyleH2Struct &result) { + auto map = (std::unordered_map)value; + + auto tmp_fontSize = map.find("fontSize"); + if (tmp_fontSize != map.end()) { + fromRawValue(context, tmp_fontSize->second, result.fontSize); + } + auto tmp_fontFamily = map.find("fontFamily"); + if (tmp_fontFamily != map.end()) { + fromRawValue(context, tmp_fontFamily->second, result.fontFamily); + } + auto tmp_fontWeight = map.find("fontWeight"); + if (tmp_fontWeight != map.end()) { + fromRawValue(context, tmp_fontWeight->second, result.fontWeight); + } + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } + auto tmp_marginTop = map.find("marginTop"); + if (tmp_marginTop != map.end()) { + fromRawValue(context, tmp_marginTop->second, result.marginTop); + } + auto tmp_marginBottom = map.find("marginBottom"); + if (tmp_marginBottom != map.end()) { + fromRawValue(context, tmp_marginBottom->second, result.marginBottom); + } + auto tmp_lineHeight = map.find("lineHeight"); + if (tmp_lineHeight != map.end()) { + fromRawValue(context, tmp_lineHeight->second, result.lineHeight); + } + auto tmp_textAlign = map.find("textAlign"); + if (tmp_textAlign != map.end()) { + fromRawValue(context, tmp_textAlign->second, result.textAlign); + } +} + +static inline std::string toString(const EnrichedMarkdownTextMarkdownStyleH2Struct &value) { + return "[Object EnrichedMarkdownTextMarkdownStyleH2Struct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownTextMarkdownStyleH2Struct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownTextMarkdownStyleH3Struct { + Float fontSize{0.0}; + std::string fontFamily{}; + std::string fontWeight{}; + SharedColor color{}; + Float marginTop{0.0}; + Float marginBottom{0.0}; + Float lineHeight{0.0}; + std::string textAlign{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownTextMarkdownStyleH3Struct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["fontSize"] = fontSize; + result["fontFamily"] = fontFamily; + result["fontWeight"] = fontWeight; + result["color"] = ::facebook::react::toDynamic(color); + result["marginTop"] = marginTop; + result["marginBottom"] = marginBottom; + result["lineHeight"] = lineHeight; + result["textAlign"] = textAlign; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownTextMarkdownStyleH3Struct &result) { + auto map = (std::unordered_map)value; + + auto tmp_fontSize = map.find("fontSize"); + if (tmp_fontSize != map.end()) { + fromRawValue(context, tmp_fontSize->second, result.fontSize); + } + auto tmp_fontFamily = map.find("fontFamily"); + if (tmp_fontFamily != map.end()) { + fromRawValue(context, tmp_fontFamily->second, result.fontFamily); + } + auto tmp_fontWeight = map.find("fontWeight"); + if (tmp_fontWeight != map.end()) { + fromRawValue(context, tmp_fontWeight->second, result.fontWeight); + } + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } + auto tmp_marginTop = map.find("marginTop"); + if (tmp_marginTop != map.end()) { + fromRawValue(context, tmp_marginTop->second, result.marginTop); + } + auto tmp_marginBottom = map.find("marginBottom"); + if (tmp_marginBottom != map.end()) { + fromRawValue(context, tmp_marginBottom->second, result.marginBottom); + } + auto tmp_lineHeight = map.find("lineHeight"); + if (tmp_lineHeight != map.end()) { + fromRawValue(context, tmp_lineHeight->second, result.lineHeight); + } + auto tmp_textAlign = map.find("textAlign"); + if (tmp_textAlign != map.end()) { + fromRawValue(context, tmp_textAlign->second, result.textAlign); + } +} + +static inline std::string toString(const EnrichedMarkdownTextMarkdownStyleH3Struct &value) { + return "[Object EnrichedMarkdownTextMarkdownStyleH3Struct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownTextMarkdownStyleH3Struct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownTextMarkdownStyleH4Struct { + Float fontSize{0.0}; + std::string fontFamily{}; + std::string fontWeight{}; + SharedColor color{}; + Float marginTop{0.0}; + Float marginBottom{0.0}; + Float lineHeight{0.0}; + std::string textAlign{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownTextMarkdownStyleH4Struct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["fontSize"] = fontSize; + result["fontFamily"] = fontFamily; + result["fontWeight"] = fontWeight; + result["color"] = ::facebook::react::toDynamic(color); + result["marginTop"] = marginTop; + result["marginBottom"] = marginBottom; + result["lineHeight"] = lineHeight; + result["textAlign"] = textAlign; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownTextMarkdownStyleH4Struct &result) { + auto map = (std::unordered_map)value; + + auto tmp_fontSize = map.find("fontSize"); + if (tmp_fontSize != map.end()) { + fromRawValue(context, tmp_fontSize->second, result.fontSize); + } + auto tmp_fontFamily = map.find("fontFamily"); + if (tmp_fontFamily != map.end()) { + fromRawValue(context, tmp_fontFamily->second, result.fontFamily); + } + auto tmp_fontWeight = map.find("fontWeight"); + if (tmp_fontWeight != map.end()) { + fromRawValue(context, tmp_fontWeight->second, result.fontWeight); + } + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } + auto tmp_marginTop = map.find("marginTop"); + if (tmp_marginTop != map.end()) { + fromRawValue(context, tmp_marginTop->second, result.marginTop); + } + auto tmp_marginBottom = map.find("marginBottom"); + if (tmp_marginBottom != map.end()) { + fromRawValue(context, tmp_marginBottom->second, result.marginBottom); + } + auto tmp_lineHeight = map.find("lineHeight"); + if (tmp_lineHeight != map.end()) { + fromRawValue(context, tmp_lineHeight->second, result.lineHeight); + } + auto tmp_textAlign = map.find("textAlign"); + if (tmp_textAlign != map.end()) { + fromRawValue(context, tmp_textAlign->second, result.textAlign); + } +} + +static inline std::string toString(const EnrichedMarkdownTextMarkdownStyleH4Struct &value) { + return "[Object EnrichedMarkdownTextMarkdownStyleH4Struct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownTextMarkdownStyleH4Struct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownTextMarkdownStyleH5Struct { + Float fontSize{0.0}; + std::string fontFamily{}; + std::string fontWeight{}; + SharedColor color{}; + Float marginTop{0.0}; + Float marginBottom{0.0}; + Float lineHeight{0.0}; + std::string textAlign{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownTextMarkdownStyleH5Struct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["fontSize"] = fontSize; + result["fontFamily"] = fontFamily; + result["fontWeight"] = fontWeight; + result["color"] = ::facebook::react::toDynamic(color); + result["marginTop"] = marginTop; + result["marginBottom"] = marginBottom; + result["lineHeight"] = lineHeight; + result["textAlign"] = textAlign; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownTextMarkdownStyleH5Struct &result) { + auto map = (std::unordered_map)value; + + auto tmp_fontSize = map.find("fontSize"); + if (tmp_fontSize != map.end()) { + fromRawValue(context, tmp_fontSize->second, result.fontSize); + } + auto tmp_fontFamily = map.find("fontFamily"); + if (tmp_fontFamily != map.end()) { + fromRawValue(context, tmp_fontFamily->second, result.fontFamily); + } + auto tmp_fontWeight = map.find("fontWeight"); + if (tmp_fontWeight != map.end()) { + fromRawValue(context, tmp_fontWeight->second, result.fontWeight); + } + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } + auto tmp_marginTop = map.find("marginTop"); + if (tmp_marginTop != map.end()) { + fromRawValue(context, tmp_marginTop->second, result.marginTop); + } + auto tmp_marginBottom = map.find("marginBottom"); + if (tmp_marginBottom != map.end()) { + fromRawValue(context, tmp_marginBottom->second, result.marginBottom); + } + auto tmp_lineHeight = map.find("lineHeight"); + if (tmp_lineHeight != map.end()) { + fromRawValue(context, tmp_lineHeight->second, result.lineHeight); + } + auto tmp_textAlign = map.find("textAlign"); + if (tmp_textAlign != map.end()) { + fromRawValue(context, tmp_textAlign->second, result.textAlign); + } +} + +static inline std::string toString(const EnrichedMarkdownTextMarkdownStyleH5Struct &value) { + return "[Object EnrichedMarkdownTextMarkdownStyleH5Struct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownTextMarkdownStyleH5Struct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownTextMarkdownStyleH6Struct { + Float fontSize{0.0}; + std::string fontFamily{}; + std::string fontWeight{}; + SharedColor color{}; + Float marginTop{0.0}; + Float marginBottom{0.0}; + Float lineHeight{0.0}; + std::string textAlign{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownTextMarkdownStyleH6Struct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["fontSize"] = fontSize; + result["fontFamily"] = fontFamily; + result["fontWeight"] = fontWeight; + result["color"] = ::facebook::react::toDynamic(color); + result["marginTop"] = marginTop; + result["marginBottom"] = marginBottom; + result["lineHeight"] = lineHeight; + result["textAlign"] = textAlign; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownTextMarkdownStyleH6Struct &result) { + auto map = (std::unordered_map)value; + + auto tmp_fontSize = map.find("fontSize"); + if (tmp_fontSize != map.end()) { + fromRawValue(context, tmp_fontSize->second, result.fontSize); + } + auto tmp_fontFamily = map.find("fontFamily"); + if (tmp_fontFamily != map.end()) { + fromRawValue(context, tmp_fontFamily->second, result.fontFamily); + } + auto tmp_fontWeight = map.find("fontWeight"); + if (tmp_fontWeight != map.end()) { + fromRawValue(context, tmp_fontWeight->second, result.fontWeight); + } + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } + auto tmp_marginTop = map.find("marginTop"); + if (tmp_marginTop != map.end()) { + fromRawValue(context, tmp_marginTop->second, result.marginTop); + } + auto tmp_marginBottom = map.find("marginBottom"); + if (tmp_marginBottom != map.end()) { + fromRawValue(context, tmp_marginBottom->second, result.marginBottom); + } + auto tmp_lineHeight = map.find("lineHeight"); + if (tmp_lineHeight != map.end()) { + fromRawValue(context, tmp_lineHeight->second, result.lineHeight); + } + auto tmp_textAlign = map.find("textAlign"); + if (tmp_textAlign != map.end()) { + fromRawValue(context, tmp_textAlign->second, result.textAlign); + } +} + +static inline std::string toString(const EnrichedMarkdownTextMarkdownStyleH6Struct &value) { + return "[Object EnrichedMarkdownTextMarkdownStyleH6Struct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownTextMarkdownStyleH6Struct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownTextMarkdownStyleBlockquoteStruct { + Float fontSize{0.0}; + std::string fontFamily{}; + std::string fontWeight{}; + SharedColor color{}; + Float marginTop{0.0}; + Float marginBottom{0.0}; + Float lineHeight{0.0}; + SharedColor borderColor{}; + Float borderWidth{0.0}; + Float gapWidth{0.0}; + SharedColor backgroundColor{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownTextMarkdownStyleBlockquoteStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["fontSize"] = fontSize; + result["fontFamily"] = fontFamily; + result["fontWeight"] = fontWeight; + result["color"] = ::facebook::react::toDynamic(color); + result["marginTop"] = marginTop; + result["marginBottom"] = marginBottom; + result["lineHeight"] = lineHeight; + result["borderColor"] = ::facebook::react::toDynamic(borderColor); + result["borderWidth"] = borderWidth; + result["gapWidth"] = gapWidth; + result["backgroundColor"] = ::facebook::react::toDynamic(backgroundColor); + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownTextMarkdownStyleBlockquoteStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_fontSize = map.find("fontSize"); + if (tmp_fontSize != map.end()) { + fromRawValue(context, tmp_fontSize->second, result.fontSize); + } + auto tmp_fontFamily = map.find("fontFamily"); + if (tmp_fontFamily != map.end()) { + fromRawValue(context, tmp_fontFamily->second, result.fontFamily); + } + auto tmp_fontWeight = map.find("fontWeight"); + if (tmp_fontWeight != map.end()) { + fromRawValue(context, tmp_fontWeight->second, result.fontWeight); + } + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } + auto tmp_marginTop = map.find("marginTop"); + if (tmp_marginTop != map.end()) { + fromRawValue(context, tmp_marginTop->second, result.marginTop); + } + auto tmp_marginBottom = map.find("marginBottom"); + if (tmp_marginBottom != map.end()) { + fromRawValue(context, tmp_marginBottom->second, result.marginBottom); + } + auto tmp_lineHeight = map.find("lineHeight"); + if (tmp_lineHeight != map.end()) { + fromRawValue(context, tmp_lineHeight->second, result.lineHeight); + } + auto tmp_borderColor = map.find("borderColor"); + if (tmp_borderColor != map.end()) { + fromRawValue(context, tmp_borderColor->second, result.borderColor); + } + auto tmp_borderWidth = map.find("borderWidth"); + if (tmp_borderWidth != map.end()) { + fromRawValue(context, tmp_borderWidth->second, result.borderWidth); + } + auto tmp_gapWidth = map.find("gapWidth"); + if (tmp_gapWidth != map.end()) { + fromRawValue(context, tmp_gapWidth->second, result.gapWidth); + } + auto tmp_backgroundColor = map.find("backgroundColor"); + if (tmp_backgroundColor != map.end()) { + fromRawValue(context, tmp_backgroundColor->second, result.backgroundColor); + } +} + +static inline std::string toString(const EnrichedMarkdownTextMarkdownStyleBlockquoteStruct &value) { + return "[Object EnrichedMarkdownTextMarkdownStyleBlockquoteStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownTextMarkdownStyleBlockquoteStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownTextMarkdownStyleListStruct { + Float fontSize{0.0}; + std::string fontFamily{}; + std::string fontWeight{}; + SharedColor color{}; + Float marginTop{0.0}; + Float marginBottom{0.0}; + Float lineHeight{0.0}; + SharedColor bulletColor{}; + Float bulletSize{0.0}; + Float markerMinWidth{0.0}; + SharedColor markerColor{}; + std::string markerFontWeight{}; + Float gapWidth{0.0}; + Float marginLeft{0.0}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownTextMarkdownStyleListStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["fontSize"] = fontSize; + result["fontFamily"] = fontFamily; + result["fontWeight"] = fontWeight; + result["color"] = ::facebook::react::toDynamic(color); + result["marginTop"] = marginTop; + result["marginBottom"] = marginBottom; + result["lineHeight"] = lineHeight; + result["bulletColor"] = ::facebook::react::toDynamic(bulletColor); + result["bulletSize"] = bulletSize; + result["markerMinWidth"] = markerMinWidth; + result["markerColor"] = ::facebook::react::toDynamic(markerColor); + result["markerFontWeight"] = markerFontWeight; + result["gapWidth"] = gapWidth; + result["marginLeft"] = marginLeft; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownTextMarkdownStyleListStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_fontSize = map.find("fontSize"); + if (tmp_fontSize != map.end()) { + fromRawValue(context, tmp_fontSize->second, result.fontSize); + } + auto tmp_fontFamily = map.find("fontFamily"); + if (tmp_fontFamily != map.end()) { + fromRawValue(context, tmp_fontFamily->second, result.fontFamily); + } + auto tmp_fontWeight = map.find("fontWeight"); + if (tmp_fontWeight != map.end()) { + fromRawValue(context, tmp_fontWeight->second, result.fontWeight); + } + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } + auto tmp_marginTop = map.find("marginTop"); + if (tmp_marginTop != map.end()) { + fromRawValue(context, tmp_marginTop->second, result.marginTop); + } + auto tmp_marginBottom = map.find("marginBottom"); + if (tmp_marginBottom != map.end()) { + fromRawValue(context, tmp_marginBottom->second, result.marginBottom); + } + auto tmp_lineHeight = map.find("lineHeight"); + if (tmp_lineHeight != map.end()) { + fromRawValue(context, tmp_lineHeight->second, result.lineHeight); + } + auto tmp_bulletColor = map.find("bulletColor"); + if (tmp_bulletColor != map.end()) { + fromRawValue(context, tmp_bulletColor->second, result.bulletColor); + } + auto tmp_bulletSize = map.find("bulletSize"); + if (tmp_bulletSize != map.end()) { + fromRawValue(context, tmp_bulletSize->second, result.bulletSize); + } + auto tmp_markerMinWidth = map.find("markerMinWidth"); + if (tmp_markerMinWidth != map.end()) { + fromRawValue(context, tmp_markerMinWidth->second, result.markerMinWidth); + } + auto tmp_markerColor = map.find("markerColor"); + if (tmp_markerColor != map.end()) { + fromRawValue(context, tmp_markerColor->second, result.markerColor); + } + auto tmp_markerFontWeight = map.find("markerFontWeight"); + if (tmp_markerFontWeight != map.end()) { + fromRawValue(context, tmp_markerFontWeight->second, result.markerFontWeight); + } + auto tmp_gapWidth = map.find("gapWidth"); + if (tmp_gapWidth != map.end()) { + fromRawValue(context, tmp_gapWidth->second, result.gapWidth); + } + auto tmp_marginLeft = map.find("marginLeft"); + if (tmp_marginLeft != map.end()) { + fromRawValue(context, tmp_marginLeft->second, result.marginLeft); + } +} + +static inline std::string toString(const EnrichedMarkdownTextMarkdownStyleListStruct &value) { + return "[Object EnrichedMarkdownTextMarkdownStyleListStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownTextMarkdownStyleListStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownTextMarkdownStyleCodeBlockStruct { + Float fontSize{0.0}; + std::string fontFamily{}; + std::string fontWeight{}; + SharedColor color{}; + Float marginTop{0.0}; + Float marginBottom{0.0}; + Float lineHeight{0.0}; + SharedColor backgroundColor{}; + SharedColor borderColor{}; + Float borderRadius{0.0}; + Float borderWidth{0.0}; + Float padding{0.0}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownTextMarkdownStyleCodeBlockStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["fontSize"] = fontSize; + result["fontFamily"] = fontFamily; + result["fontWeight"] = fontWeight; + result["color"] = ::facebook::react::toDynamic(color); + result["marginTop"] = marginTop; + result["marginBottom"] = marginBottom; + result["lineHeight"] = lineHeight; + result["backgroundColor"] = ::facebook::react::toDynamic(backgroundColor); + result["borderColor"] = ::facebook::react::toDynamic(borderColor); + result["borderRadius"] = borderRadius; + result["borderWidth"] = borderWidth; + result["padding"] = padding; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownTextMarkdownStyleCodeBlockStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_fontSize = map.find("fontSize"); + if (tmp_fontSize != map.end()) { + fromRawValue(context, tmp_fontSize->second, result.fontSize); + } + auto tmp_fontFamily = map.find("fontFamily"); + if (tmp_fontFamily != map.end()) { + fromRawValue(context, tmp_fontFamily->second, result.fontFamily); + } + auto tmp_fontWeight = map.find("fontWeight"); + if (tmp_fontWeight != map.end()) { + fromRawValue(context, tmp_fontWeight->second, result.fontWeight); + } + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } + auto tmp_marginTop = map.find("marginTop"); + if (tmp_marginTop != map.end()) { + fromRawValue(context, tmp_marginTop->second, result.marginTop); + } + auto tmp_marginBottom = map.find("marginBottom"); + if (tmp_marginBottom != map.end()) { + fromRawValue(context, tmp_marginBottom->second, result.marginBottom); + } + auto tmp_lineHeight = map.find("lineHeight"); + if (tmp_lineHeight != map.end()) { + fromRawValue(context, tmp_lineHeight->second, result.lineHeight); + } + auto tmp_backgroundColor = map.find("backgroundColor"); + if (tmp_backgroundColor != map.end()) { + fromRawValue(context, tmp_backgroundColor->second, result.backgroundColor); + } + auto tmp_borderColor = map.find("borderColor"); + if (tmp_borderColor != map.end()) { + fromRawValue(context, tmp_borderColor->second, result.borderColor); + } + auto tmp_borderRadius = map.find("borderRadius"); + if (tmp_borderRadius != map.end()) { + fromRawValue(context, tmp_borderRadius->second, result.borderRadius); + } + auto tmp_borderWidth = map.find("borderWidth"); + if (tmp_borderWidth != map.end()) { + fromRawValue(context, tmp_borderWidth->second, result.borderWidth); + } + auto tmp_padding = map.find("padding"); + if (tmp_padding != map.end()) { + fromRawValue(context, tmp_padding->second, result.padding); + } +} + +static inline std::string toString(const EnrichedMarkdownTextMarkdownStyleCodeBlockStruct &value) { + return "[Object EnrichedMarkdownTextMarkdownStyleCodeBlockStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownTextMarkdownStyleCodeBlockStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownTextMarkdownStyleLinkStruct { + std::string fontFamily{}; + SharedColor color{}; + bool underline{false}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownTextMarkdownStyleLinkStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["fontFamily"] = fontFamily; + result["color"] = ::facebook::react::toDynamic(color); + result["underline"] = underline; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownTextMarkdownStyleLinkStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_fontFamily = map.find("fontFamily"); + if (tmp_fontFamily != map.end()) { + fromRawValue(context, tmp_fontFamily->second, result.fontFamily); + } + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } + auto tmp_underline = map.find("underline"); + if (tmp_underline != map.end()) { + fromRawValue(context, tmp_underline->second, result.underline); + } +} + +static inline std::string toString(const EnrichedMarkdownTextMarkdownStyleLinkStruct &value) { + return "[Object EnrichedMarkdownTextMarkdownStyleLinkStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownTextMarkdownStyleLinkStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownTextMarkdownStyleStrongStruct { + std::string fontFamily{}; + std::string fontWeight{}; + SharedColor color{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownTextMarkdownStyleStrongStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["fontFamily"] = fontFamily; + result["fontWeight"] = fontWeight; + result["color"] = ::facebook::react::toDynamic(color); + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownTextMarkdownStyleStrongStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_fontFamily = map.find("fontFamily"); + if (tmp_fontFamily != map.end()) { + fromRawValue(context, tmp_fontFamily->second, result.fontFamily); + } + auto tmp_fontWeight = map.find("fontWeight"); + if (tmp_fontWeight != map.end()) { + fromRawValue(context, tmp_fontWeight->second, result.fontWeight); + } + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } +} + +static inline std::string toString(const EnrichedMarkdownTextMarkdownStyleStrongStruct &value) { + return "[Object EnrichedMarkdownTextMarkdownStyleStrongStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownTextMarkdownStyleStrongStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownTextMarkdownStyleEmStruct { + std::string fontFamily{}; + std::string fontStyle{}; + SharedColor color{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownTextMarkdownStyleEmStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["fontFamily"] = fontFamily; + result["fontStyle"] = fontStyle; + result["color"] = ::facebook::react::toDynamic(color); + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownTextMarkdownStyleEmStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_fontFamily = map.find("fontFamily"); + if (tmp_fontFamily != map.end()) { + fromRawValue(context, tmp_fontFamily->second, result.fontFamily); + } + auto tmp_fontStyle = map.find("fontStyle"); + if (tmp_fontStyle != map.end()) { + fromRawValue(context, tmp_fontStyle->second, result.fontStyle); + } + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } +} + +static inline std::string toString(const EnrichedMarkdownTextMarkdownStyleEmStruct &value) { + return "[Object EnrichedMarkdownTextMarkdownStyleEmStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownTextMarkdownStyleEmStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownTextMarkdownStyleStrikethroughStruct { + SharedColor color{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownTextMarkdownStyleStrikethroughStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["color"] = ::facebook::react::toDynamic(color); + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownTextMarkdownStyleStrikethroughStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } +} + +static inline std::string toString(const EnrichedMarkdownTextMarkdownStyleStrikethroughStruct &value) { + return "[Object EnrichedMarkdownTextMarkdownStyleStrikethroughStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownTextMarkdownStyleStrikethroughStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownTextMarkdownStyleUnderlineStruct { + SharedColor color{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownTextMarkdownStyleUnderlineStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["color"] = ::facebook::react::toDynamic(color); + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownTextMarkdownStyleUnderlineStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } +} + +static inline std::string toString(const EnrichedMarkdownTextMarkdownStyleUnderlineStruct &value) { + return "[Object EnrichedMarkdownTextMarkdownStyleUnderlineStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownTextMarkdownStyleUnderlineStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownTextMarkdownStyleCodeStruct { + std::string fontFamily{}; + Float fontSize{0.0}; + SharedColor color{}; + SharedColor backgroundColor{}; + SharedColor borderColor{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownTextMarkdownStyleCodeStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["fontFamily"] = fontFamily; + result["fontSize"] = fontSize; + result["color"] = ::facebook::react::toDynamic(color); + result["backgroundColor"] = ::facebook::react::toDynamic(backgroundColor); + result["borderColor"] = ::facebook::react::toDynamic(borderColor); + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownTextMarkdownStyleCodeStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_fontFamily = map.find("fontFamily"); + if (tmp_fontFamily != map.end()) { + fromRawValue(context, tmp_fontFamily->second, result.fontFamily); + } + auto tmp_fontSize = map.find("fontSize"); + if (tmp_fontSize != map.end()) { + fromRawValue(context, tmp_fontSize->second, result.fontSize); + } + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } + auto tmp_backgroundColor = map.find("backgroundColor"); + if (tmp_backgroundColor != map.end()) { + fromRawValue(context, tmp_backgroundColor->second, result.backgroundColor); + } + auto tmp_borderColor = map.find("borderColor"); + if (tmp_borderColor != map.end()) { + fromRawValue(context, tmp_borderColor->second, result.borderColor); + } +} + +static inline std::string toString(const EnrichedMarkdownTextMarkdownStyleCodeStruct &value) { + return "[Object EnrichedMarkdownTextMarkdownStyleCodeStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownTextMarkdownStyleCodeStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownTextMarkdownStyleImageStruct { + Float height{0.0}; + Float borderRadius{0.0}; + Float marginTop{0.0}; + Float marginBottom{0.0}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownTextMarkdownStyleImageStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["height"] = height; + result["borderRadius"] = borderRadius; + result["marginTop"] = marginTop; + result["marginBottom"] = marginBottom; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownTextMarkdownStyleImageStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_height = map.find("height"); + if (tmp_height != map.end()) { + fromRawValue(context, tmp_height->second, result.height); + } + auto tmp_borderRadius = map.find("borderRadius"); + if (tmp_borderRadius != map.end()) { + fromRawValue(context, tmp_borderRadius->second, result.borderRadius); + } + auto tmp_marginTop = map.find("marginTop"); + if (tmp_marginTop != map.end()) { + fromRawValue(context, tmp_marginTop->second, result.marginTop); + } + auto tmp_marginBottom = map.find("marginBottom"); + if (tmp_marginBottom != map.end()) { + fromRawValue(context, tmp_marginBottom->second, result.marginBottom); + } +} + +static inline std::string toString(const EnrichedMarkdownTextMarkdownStyleImageStruct &value) { + return "[Object EnrichedMarkdownTextMarkdownStyleImageStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownTextMarkdownStyleImageStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownTextMarkdownStyleInlineImageStruct { + Float size{0.0}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownTextMarkdownStyleInlineImageStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["size"] = size; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownTextMarkdownStyleInlineImageStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_size = map.find("size"); + if (tmp_size != map.end()) { + fromRawValue(context, tmp_size->second, result.size); + } +} + +static inline std::string toString(const EnrichedMarkdownTextMarkdownStyleInlineImageStruct &value) { + return "[Object EnrichedMarkdownTextMarkdownStyleInlineImageStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownTextMarkdownStyleInlineImageStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownTextMarkdownStyleThematicBreakStruct { + SharedColor color{}; + Float height{0.0}; + Float marginTop{0.0}; + Float marginBottom{0.0}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownTextMarkdownStyleThematicBreakStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["color"] = ::facebook::react::toDynamic(color); + result["height"] = height; + result["marginTop"] = marginTop; + result["marginBottom"] = marginBottom; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownTextMarkdownStyleThematicBreakStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } + auto tmp_height = map.find("height"); + if (tmp_height != map.end()) { + fromRawValue(context, tmp_height->second, result.height); + } + auto tmp_marginTop = map.find("marginTop"); + if (tmp_marginTop != map.end()) { + fromRawValue(context, tmp_marginTop->second, result.marginTop); + } + auto tmp_marginBottom = map.find("marginBottom"); + if (tmp_marginBottom != map.end()) { + fromRawValue(context, tmp_marginBottom->second, result.marginBottom); + } +} + +static inline std::string toString(const EnrichedMarkdownTextMarkdownStyleThematicBreakStruct &value) { + return "[Object EnrichedMarkdownTextMarkdownStyleThematicBreakStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownTextMarkdownStyleThematicBreakStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownTextMarkdownStyleTableStruct { + Float fontSize{0.0}; + std::string fontFamily{}; + std::string fontWeight{}; + SharedColor color{}; + Float marginTop{0.0}; + Float marginBottom{0.0}; + Float lineHeight{0.0}; + std::string headerFontFamily{}; + SharedColor headerBackgroundColor{}; + SharedColor headerTextColor{}; + SharedColor rowEvenBackgroundColor{}; + SharedColor rowOddBackgroundColor{}; + SharedColor borderColor{}; + Float borderWidth{0.0}; + Float borderRadius{0.0}; + Float cellPaddingHorizontal{0.0}; + Float cellPaddingVertical{0.0}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownTextMarkdownStyleTableStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["fontSize"] = fontSize; + result["fontFamily"] = fontFamily; + result["fontWeight"] = fontWeight; + result["color"] = ::facebook::react::toDynamic(color); + result["marginTop"] = marginTop; + result["marginBottom"] = marginBottom; + result["lineHeight"] = lineHeight; + result["headerFontFamily"] = headerFontFamily; + result["headerBackgroundColor"] = ::facebook::react::toDynamic(headerBackgroundColor); + result["headerTextColor"] = ::facebook::react::toDynamic(headerTextColor); + result["rowEvenBackgroundColor"] = ::facebook::react::toDynamic(rowEvenBackgroundColor); + result["rowOddBackgroundColor"] = ::facebook::react::toDynamic(rowOddBackgroundColor); + result["borderColor"] = ::facebook::react::toDynamic(borderColor); + result["borderWidth"] = borderWidth; + result["borderRadius"] = borderRadius; + result["cellPaddingHorizontal"] = cellPaddingHorizontal; + result["cellPaddingVertical"] = cellPaddingVertical; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownTextMarkdownStyleTableStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_fontSize = map.find("fontSize"); + if (tmp_fontSize != map.end()) { + fromRawValue(context, tmp_fontSize->second, result.fontSize); + } + auto tmp_fontFamily = map.find("fontFamily"); + if (tmp_fontFamily != map.end()) { + fromRawValue(context, tmp_fontFamily->second, result.fontFamily); + } + auto tmp_fontWeight = map.find("fontWeight"); + if (tmp_fontWeight != map.end()) { + fromRawValue(context, tmp_fontWeight->second, result.fontWeight); + } + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } + auto tmp_marginTop = map.find("marginTop"); + if (tmp_marginTop != map.end()) { + fromRawValue(context, tmp_marginTop->second, result.marginTop); + } + auto tmp_marginBottom = map.find("marginBottom"); + if (tmp_marginBottom != map.end()) { + fromRawValue(context, tmp_marginBottom->second, result.marginBottom); + } + auto tmp_lineHeight = map.find("lineHeight"); + if (tmp_lineHeight != map.end()) { + fromRawValue(context, tmp_lineHeight->second, result.lineHeight); + } + auto tmp_headerFontFamily = map.find("headerFontFamily"); + if (tmp_headerFontFamily != map.end()) { + fromRawValue(context, tmp_headerFontFamily->second, result.headerFontFamily); + } + auto tmp_headerBackgroundColor = map.find("headerBackgroundColor"); + if (tmp_headerBackgroundColor != map.end()) { + fromRawValue(context, tmp_headerBackgroundColor->second, result.headerBackgroundColor); + } + auto tmp_headerTextColor = map.find("headerTextColor"); + if (tmp_headerTextColor != map.end()) { + fromRawValue(context, tmp_headerTextColor->second, result.headerTextColor); + } + auto tmp_rowEvenBackgroundColor = map.find("rowEvenBackgroundColor"); + if (tmp_rowEvenBackgroundColor != map.end()) { + fromRawValue(context, tmp_rowEvenBackgroundColor->second, result.rowEvenBackgroundColor); + } + auto tmp_rowOddBackgroundColor = map.find("rowOddBackgroundColor"); + if (tmp_rowOddBackgroundColor != map.end()) { + fromRawValue(context, tmp_rowOddBackgroundColor->second, result.rowOddBackgroundColor); + } + auto tmp_borderColor = map.find("borderColor"); + if (tmp_borderColor != map.end()) { + fromRawValue(context, tmp_borderColor->second, result.borderColor); + } + auto tmp_borderWidth = map.find("borderWidth"); + if (tmp_borderWidth != map.end()) { + fromRawValue(context, tmp_borderWidth->second, result.borderWidth); + } + auto tmp_borderRadius = map.find("borderRadius"); + if (tmp_borderRadius != map.end()) { + fromRawValue(context, tmp_borderRadius->second, result.borderRadius); + } + auto tmp_cellPaddingHorizontal = map.find("cellPaddingHorizontal"); + if (tmp_cellPaddingHorizontal != map.end()) { + fromRawValue(context, tmp_cellPaddingHorizontal->second, result.cellPaddingHorizontal); + } + auto tmp_cellPaddingVertical = map.find("cellPaddingVertical"); + if (tmp_cellPaddingVertical != map.end()) { + fromRawValue(context, tmp_cellPaddingVertical->second, result.cellPaddingVertical); + } +} + +static inline std::string toString(const EnrichedMarkdownTextMarkdownStyleTableStruct &value) { + return "[Object EnrichedMarkdownTextMarkdownStyleTableStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownTextMarkdownStyleTableStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownTextMarkdownStyleTaskListStruct { + SharedColor checkedColor{}; + SharedColor borderColor{}; + Float checkboxSize{0.0}; + Float checkboxBorderRadius{0.0}; + SharedColor checkmarkColor{}; + SharedColor checkedTextColor{}; + bool checkedStrikethrough{false}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownTextMarkdownStyleTaskListStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["checkedColor"] = ::facebook::react::toDynamic(checkedColor); + result["borderColor"] = ::facebook::react::toDynamic(borderColor); + result["checkboxSize"] = checkboxSize; + result["checkboxBorderRadius"] = checkboxBorderRadius; + result["checkmarkColor"] = ::facebook::react::toDynamic(checkmarkColor); + result["checkedTextColor"] = ::facebook::react::toDynamic(checkedTextColor); + result["checkedStrikethrough"] = checkedStrikethrough; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownTextMarkdownStyleTaskListStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_checkedColor = map.find("checkedColor"); + if (tmp_checkedColor != map.end()) { + fromRawValue(context, tmp_checkedColor->second, result.checkedColor); + } + auto tmp_borderColor = map.find("borderColor"); + if (tmp_borderColor != map.end()) { + fromRawValue(context, tmp_borderColor->second, result.borderColor); + } + auto tmp_checkboxSize = map.find("checkboxSize"); + if (tmp_checkboxSize != map.end()) { + fromRawValue(context, tmp_checkboxSize->second, result.checkboxSize); + } + auto tmp_checkboxBorderRadius = map.find("checkboxBorderRadius"); + if (tmp_checkboxBorderRadius != map.end()) { + fromRawValue(context, tmp_checkboxBorderRadius->second, result.checkboxBorderRadius); + } + auto tmp_checkmarkColor = map.find("checkmarkColor"); + if (tmp_checkmarkColor != map.end()) { + fromRawValue(context, tmp_checkmarkColor->second, result.checkmarkColor); + } + auto tmp_checkedTextColor = map.find("checkedTextColor"); + if (tmp_checkedTextColor != map.end()) { + fromRawValue(context, tmp_checkedTextColor->second, result.checkedTextColor); + } + auto tmp_checkedStrikethrough = map.find("checkedStrikethrough"); + if (tmp_checkedStrikethrough != map.end()) { + fromRawValue(context, tmp_checkedStrikethrough->second, result.checkedStrikethrough); + } +} + +static inline std::string toString(const EnrichedMarkdownTextMarkdownStyleTaskListStruct &value) { + return "[Object EnrichedMarkdownTextMarkdownStyleTaskListStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownTextMarkdownStyleTaskListStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownTextMarkdownStyleMathStruct { + Float fontSize{0.0}; + SharedColor color{}; + SharedColor backgroundColor{}; + Float padding{0.0}; + Float marginTop{0.0}; + Float marginBottom{0.0}; + std::string textAlign{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownTextMarkdownStyleMathStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["fontSize"] = fontSize; + result["color"] = ::facebook::react::toDynamic(color); + result["backgroundColor"] = ::facebook::react::toDynamic(backgroundColor); + result["padding"] = padding; + result["marginTop"] = marginTop; + result["marginBottom"] = marginBottom; + result["textAlign"] = textAlign; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownTextMarkdownStyleMathStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_fontSize = map.find("fontSize"); + if (tmp_fontSize != map.end()) { + fromRawValue(context, tmp_fontSize->second, result.fontSize); + } + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } + auto tmp_backgroundColor = map.find("backgroundColor"); + if (tmp_backgroundColor != map.end()) { + fromRawValue(context, tmp_backgroundColor->second, result.backgroundColor); + } + auto tmp_padding = map.find("padding"); + if (tmp_padding != map.end()) { + fromRawValue(context, tmp_padding->second, result.padding); + } + auto tmp_marginTop = map.find("marginTop"); + if (tmp_marginTop != map.end()) { + fromRawValue(context, tmp_marginTop->second, result.marginTop); + } + auto tmp_marginBottom = map.find("marginBottom"); + if (tmp_marginBottom != map.end()) { + fromRawValue(context, tmp_marginBottom->second, result.marginBottom); + } + auto tmp_textAlign = map.find("textAlign"); + if (tmp_textAlign != map.end()) { + fromRawValue(context, tmp_textAlign->second, result.textAlign); + } +} + +static inline std::string toString(const EnrichedMarkdownTextMarkdownStyleMathStruct &value) { + return "[Object EnrichedMarkdownTextMarkdownStyleMathStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownTextMarkdownStyleMathStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownTextMarkdownStyleInlineMathStruct { + SharedColor color{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownTextMarkdownStyleInlineMathStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["color"] = ::facebook::react::toDynamic(color); + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownTextMarkdownStyleInlineMathStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } +} + +static inline std::string toString(const EnrichedMarkdownTextMarkdownStyleInlineMathStruct &value) { + return "[Object EnrichedMarkdownTextMarkdownStyleInlineMathStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownTextMarkdownStyleInlineMathStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownTextMarkdownStyleSpoilerParticlesStruct { + Float density{0.0}; + Float speed{0.0}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownTextMarkdownStyleSpoilerParticlesStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["density"] = density; + result["speed"] = speed; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownTextMarkdownStyleSpoilerParticlesStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_density = map.find("density"); + if (tmp_density != map.end()) { + fromRawValue(context, tmp_density->second, result.density); + } + auto tmp_speed = map.find("speed"); + if (tmp_speed != map.end()) { + fromRawValue(context, tmp_speed->second, result.speed); + } +} + +static inline std::string toString(const EnrichedMarkdownTextMarkdownStyleSpoilerParticlesStruct &value) { + return "[Object EnrichedMarkdownTextMarkdownStyleSpoilerParticlesStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownTextMarkdownStyleSpoilerParticlesStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownTextMarkdownStyleSpoilerSolidStruct { + Float borderRadius{0.0}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownTextMarkdownStyleSpoilerSolidStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["borderRadius"] = borderRadius; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownTextMarkdownStyleSpoilerSolidStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_borderRadius = map.find("borderRadius"); + if (tmp_borderRadius != map.end()) { + fromRawValue(context, tmp_borderRadius->second, result.borderRadius); + } +} + +static inline std::string toString(const EnrichedMarkdownTextMarkdownStyleSpoilerSolidStruct &value) { + return "[Object EnrichedMarkdownTextMarkdownStyleSpoilerSolidStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownTextMarkdownStyleSpoilerSolidStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownTextMarkdownStyleSpoilerStruct { + SharedColor color{}; + EnrichedMarkdownTextMarkdownStyleSpoilerParticlesStruct particles{}; + EnrichedMarkdownTextMarkdownStyleSpoilerSolidStruct solid{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownTextMarkdownStyleSpoilerStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["color"] = ::facebook::react::toDynamic(color); + result["particles"] = ::facebook::react::toDynamic(particles); + result["solid"] = ::facebook::react::toDynamic(solid); + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownTextMarkdownStyleSpoilerStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } + auto tmp_particles = map.find("particles"); + if (tmp_particles != map.end()) { + fromRawValue(context, tmp_particles->second, result.particles); + } + auto tmp_solid = map.find("solid"); + if (tmp_solid != map.end()) { + fromRawValue(context, tmp_solid->second, result.solid); + } +} + +static inline std::string toString(const EnrichedMarkdownTextMarkdownStyleSpoilerStruct &value) { + return "[Object EnrichedMarkdownTextMarkdownStyleSpoilerStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownTextMarkdownStyleSpoilerStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownTextMarkdownStyleMentionStruct { + SharedColor color{}; + SharedColor backgroundColor{}; + SharedColor borderColor{}; + Float borderWidth{0.0}; + Float borderRadius{0.0}; + Float paddingHorizontal{0.0}; + Float paddingVertical{0.0}; + std::string fontFamily{}; + std::string fontWeight{}; + Float fontSize{0.0}; + Float pressedOpacity{0.0}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownTextMarkdownStyleMentionStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["color"] = ::facebook::react::toDynamic(color); + result["backgroundColor"] = ::facebook::react::toDynamic(backgroundColor); + result["borderColor"] = ::facebook::react::toDynamic(borderColor); + result["borderWidth"] = borderWidth; + result["borderRadius"] = borderRadius; + result["paddingHorizontal"] = paddingHorizontal; + result["paddingVertical"] = paddingVertical; + result["fontFamily"] = fontFamily; + result["fontWeight"] = fontWeight; + result["fontSize"] = fontSize; + result["pressedOpacity"] = pressedOpacity; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownTextMarkdownStyleMentionStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } + auto tmp_backgroundColor = map.find("backgroundColor"); + if (tmp_backgroundColor != map.end()) { + fromRawValue(context, tmp_backgroundColor->second, result.backgroundColor); + } + auto tmp_borderColor = map.find("borderColor"); + if (tmp_borderColor != map.end()) { + fromRawValue(context, tmp_borderColor->second, result.borderColor); + } + auto tmp_borderWidth = map.find("borderWidth"); + if (tmp_borderWidth != map.end()) { + fromRawValue(context, tmp_borderWidth->second, result.borderWidth); + } + auto tmp_borderRadius = map.find("borderRadius"); + if (tmp_borderRadius != map.end()) { + fromRawValue(context, tmp_borderRadius->second, result.borderRadius); + } + auto tmp_paddingHorizontal = map.find("paddingHorizontal"); + if (tmp_paddingHorizontal != map.end()) { + fromRawValue(context, tmp_paddingHorizontal->second, result.paddingHorizontal); + } + auto tmp_paddingVertical = map.find("paddingVertical"); + if (tmp_paddingVertical != map.end()) { + fromRawValue(context, tmp_paddingVertical->second, result.paddingVertical); + } + auto tmp_fontFamily = map.find("fontFamily"); + if (tmp_fontFamily != map.end()) { + fromRawValue(context, tmp_fontFamily->second, result.fontFamily); + } + auto tmp_fontWeight = map.find("fontWeight"); + if (tmp_fontWeight != map.end()) { + fromRawValue(context, tmp_fontWeight->second, result.fontWeight); + } + auto tmp_fontSize = map.find("fontSize"); + if (tmp_fontSize != map.end()) { + fromRawValue(context, tmp_fontSize->second, result.fontSize); + } + auto tmp_pressedOpacity = map.find("pressedOpacity"); + if (tmp_pressedOpacity != map.end()) { + fromRawValue(context, tmp_pressedOpacity->second, result.pressedOpacity); + } +} + +static inline std::string toString(const EnrichedMarkdownTextMarkdownStyleMentionStruct &value) { + return "[Object EnrichedMarkdownTextMarkdownStyleMentionStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownTextMarkdownStyleMentionStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownTextMarkdownStyleCitationStruct { + SharedColor color{}; + Float fontSizeMultiplier{0.0}; + Float baselineOffsetPx{0.0}; + std::string fontWeight{}; + bool underline{false}; + SharedColor backgroundColor{}; + Float paddingHorizontal{0.0}; + Float paddingVertical{0.0}; + SharedColor borderColor{}; + Float borderWidth{0.0}; + Float borderRadius{0.0}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownTextMarkdownStyleCitationStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["color"] = ::facebook::react::toDynamic(color); + result["fontSizeMultiplier"] = fontSizeMultiplier; + result["baselineOffsetPx"] = baselineOffsetPx; + result["fontWeight"] = fontWeight; + result["underline"] = underline; + result["backgroundColor"] = ::facebook::react::toDynamic(backgroundColor); + result["paddingHorizontal"] = paddingHorizontal; + result["paddingVertical"] = paddingVertical; + result["borderColor"] = ::facebook::react::toDynamic(borderColor); + result["borderWidth"] = borderWidth; + result["borderRadius"] = borderRadius; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownTextMarkdownStyleCitationStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } + auto tmp_fontSizeMultiplier = map.find("fontSizeMultiplier"); + if (tmp_fontSizeMultiplier != map.end()) { + fromRawValue(context, tmp_fontSizeMultiplier->second, result.fontSizeMultiplier); + } + auto tmp_baselineOffsetPx = map.find("baselineOffsetPx"); + if (tmp_baselineOffsetPx != map.end()) { + fromRawValue(context, tmp_baselineOffsetPx->second, result.baselineOffsetPx); + } + auto tmp_fontWeight = map.find("fontWeight"); + if (tmp_fontWeight != map.end()) { + fromRawValue(context, tmp_fontWeight->second, result.fontWeight); + } + auto tmp_underline = map.find("underline"); + if (tmp_underline != map.end()) { + fromRawValue(context, tmp_underline->second, result.underline); + } + auto tmp_backgroundColor = map.find("backgroundColor"); + if (tmp_backgroundColor != map.end()) { + fromRawValue(context, tmp_backgroundColor->second, result.backgroundColor); + } + auto tmp_paddingHorizontal = map.find("paddingHorizontal"); + if (tmp_paddingHorizontal != map.end()) { + fromRawValue(context, tmp_paddingHorizontal->second, result.paddingHorizontal); + } + auto tmp_paddingVertical = map.find("paddingVertical"); + if (tmp_paddingVertical != map.end()) { + fromRawValue(context, tmp_paddingVertical->second, result.paddingVertical); + } + auto tmp_borderColor = map.find("borderColor"); + if (tmp_borderColor != map.end()) { + fromRawValue(context, tmp_borderColor->second, result.borderColor); + } + auto tmp_borderWidth = map.find("borderWidth"); + if (tmp_borderWidth != map.end()) { + fromRawValue(context, tmp_borderWidth->second, result.borderWidth); + } + auto tmp_borderRadius = map.find("borderRadius"); + if (tmp_borderRadius != map.end()) { + fromRawValue(context, tmp_borderRadius->second, result.borderRadius); + } +} + +static inline std::string toString(const EnrichedMarkdownTextMarkdownStyleCitationStruct &value) { + return "[Object EnrichedMarkdownTextMarkdownStyleCitationStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownTextMarkdownStyleCitationStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownTextMarkdownStyleStruct { + EnrichedMarkdownTextMarkdownStyleParagraphStruct paragraph{}; + EnrichedMarkdownTextMarkdownStyleH1Struct h1{}; + EnrichedMarkdownTextMarkdownStyleH2Struct h2{}; + EnrichedMarkdownTextMarkdownStyleH3Struct h3{}; + EnrichedMarkdownTextMarkdownStyleH4Struct h4{}; + EnrichedMarkdownTextMarkdownStyleH5Struct h5{}; + EnrichedMarkdownTextMarkdownStyleH6Struct h6{}; + EnrichedMarkdownTextMarkdownStyleBlockquoteStruct blockquote{}; + EnrichedMarkdownTextMarkdownStyleListStruct list{}; + EnrichedMarkdownTextMarkdownStyleCodeBlockStruct codeBlock{}; + EnrichedMarkdownTextMarkdownStyleLinkStruct link{}; + EnrichedMarkdownTextMarkdownStyleStrongStruct strong{}; + EnrichedMarkdownTextMarkdownStyleEmStruct em{}; + EnrichedMarkdownTextMarkdownStyleStrikethroughStruct strikethrough{}; + EnrichedMarkdownTextMarkdownStyleUnderlineStruct underline{}; + EnrichedMarkdownTextMarkdownStyleCodeStruct code{}; + EnrichedMarkdownTextMarkdownStyleImageStruct image{}; + EnrichedMarkdownTextMarkdownStyleInlineImageStruct inlineImage{}; + EnrichedMarkdownTextMarkdownStyleThematicBreakStruct thematicBreak{}; + EnrichedMarkdownTextMarkdownStyleTableStruct table{}; + EnrichedMarkdownTextMarkdownStyleTaskListStruct taskList{}; + EnrichedMarkdownTextMarkdownStyleMathStruct math{}; + EnrichedMarkdownTextMarkdownStyleInlineMathStruct inlineMath{}; + EnrichedMarkdownTextMarkdownStyleSpoilerStruct spoiler{}; + EnrichedMarkdownTextMarkdownStyleMentionStruct mention{}; + EnrichedMarkdownTextMarkdownStyleCitationStruct citation{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownTextMarkdownStyleStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["paragraph"] = ::facebook::react::toDynamic(paragraph); + result["h1"] = ::facebook::react::toDynamic(h1); + result["h2"] = ::facebook::react::toDynamic(h2); + result["h3"] = ::facebook::react::toDynamic(h3); + result["h4"] = ::facebook::react::toDynamic(h4); + result["h5"] = ::facebook::react::toDynamic(h5); + result["h6"] = ::facebook::react::toDynamic(h6); + result["blockquote"] = ::facebook::react::toDynamic(blockquote); + result["list"] = ::facebook::react::toDynamic(list); + result["codeBlock"] = ::facebook::react::toDynamic(codeBlock); + result["link"] = ::facebook::react::toDynamic(link); + result["strong"] = ::facebook::react::toDynamic(strong); + result["em"] = ::facebook::react::toDynamic(em); + result["strikethrough"] = ::facebook::react::toDynamic(strikethrough); + result["underline"] = ::facebook::react::toDynamic(underline); + result["code"] = ::facebook::react::toDynamic(code); + result["image"] = ::facebook::react::toDynamic(image); + result["inlineImage"] = ::facebook::react::toDynamic(inlineImage); + result["thematicBreak"] = ::facebook::react::toDynamic(thematicBreak); + result["table"] = ::facebook::react::toDynamic(table); + result["taskList"] = ::facebook::react::toDynamic(taskList); + result["math"] = ::facebook::react::toDynamic(math); + result["inlineMath"] = ::facebook::react::toDynamic(inlineMath); + result["spoiler"] = ::facebook::react::toDynamic(spoiler); + result["mention"] = ::facebook::react::toDynamic(mention); + result["citation"] = ::facebook::react::toDynamic(citation); + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownTextMarkdownStyleStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_paragraph = map.find("paragraph"); + if (tmp_paragraph != map.end()) { + fromRawValue(context, tmp_paragraph->second, result.paragraph); + } + auto tmp_h1 = map.find("h1"); + if (tmp_h1 != map.end()) { + fromRawValue(context, tmp_h1->second, result.h1); + } + auto tmp_h2 = map.find("h2"); + if (tmp_h2 != map.end()) { + fromRawValue(context, tmp_h2->second, result.h2); + } + auto tmp_h3 = map.find("h3"); + if (tmp_h3 != map.end()) { + fromRawValue(context, tmp_h3->second, result.h3); + } + auto tmp_h4 = map.find("h4"); + if (tmp_h4 != map.end()) { + fromRawValue(context, tmp_h4->second, result.h4); + } + auto tmp_h5 = map.find("h5"); + if (tmp_h5 != map.end()) { + fromRawValue(context, tmp_h5->second, result.h5); + } + auto tmp_h6 = map.find("h6"); + if (tmp_h6 != map.end()) { + fromRawValue(context, tmp_h6->second, result.h6); + } + auto tmp_blockquote = map.find("blockquote"); + if (tmp_blockquote != map.end()) { + fromRawValue(context, tmp_blockquote->second, result.blockquote); + } + auto tmp_list = map.find("list"); + if (tmp_list != map.end()) { + fromRawValue(context, tmp_list->second, result.list); + } + auto tmp_codeBlock = map.find("codeBlock"); + if (tmp_codeBlock != map.end()) { + fromRawValue(context, tmp_codeBlock->second, result.codeBlock); + } + auto tmp_link = map.find("link"); + if (tmp_link != map.end()) { + fromRawValue(context, tmp_link->second, result.link); + } + auto tmp_strong = map.find("strong"); + if (tmp_strong != map.end()) { + fromRawValue(context, tmp_strong->second, result.strong); + } + auto tmp_em = map.find("em"); + if (tmp_em != map.end()) { + fromRawValue(context, tmp_em->second, result.em); + } + auto tmp_strikethrough = map.find("strikethrough"); + if (tmp_strikethrough != map.end()) { + fromRawValue(context, tmp_strikethrough->second, result.strikethrough); + } + auto tmp_underline = map.find("underline"); + if (tmp_underline != map.end()) { + fromRawValue(context, tmp_underline->second, result.underline); + } + auto tmp_code = map.find("code"); + if (tmp_code != map.end()) { + fromRawValue(context, tmp_code->second, result.code); + } + auto tmp_image = map.find("image"); + if (tmp_image != map.end()) { + fromRawValue(context, tmp_image->second, result.image); + } + auto tmp_inlineImage = map.find("inlineImage"); + if (tmp_inlineImage != map.end()) { + fromRawValue(context, tmp_inlineImage->second, result.inlineImage); + } + auto tmp_thematicBreak = map.find("thematicBreak"); + if (tmp_thematicBreak != map.end()) { + fromRawValue(context, tmp_thematicBreak->second, result.thematicBreak); + } + auto tmp_table = map.find("table"); + if (tmp_table != map.end()) { + fromRawValue(context, tmp_table->second, result.table); + } + auto tmp_taskList = map.find("taskList"); + if (tmp_taskList != map.end()) { + fromRawValue(context, tmp_taskList->second, result.taskList); + } + auto tmp_math = map.find("math"); + if (tmp_math != map.end()) { + fromRawValue(context, tmp_math->second, result.math); + } + auto tmp_inlineMath = map.find("inlineMath"); + if (tmp_inlineMath != map.end()) { + fromRawValue(context, tmp_inlineMath->second, result.inlineMath); + } + auto tmp_spoiler = map.find("spoiler"); + if (tmp_spoiler != map.end()) { + fromRawValue(context, tmp_spoiler->second, result.spoiler); + } + auto tmp_mention = map.find("mention"); + if (tmp_mention != map.end()) { + fromRawValue(context, tmp_mention->second, result.mention); + } + auto tmp_citation = map.find("citation"); + if (tmp_citation != map.end()) { + fromRawValue(context, tmp_citation->second, result.citation); + } +} + +static inline std::string toString(const EnrichedMarkdownTextMarkdownStyleStruct &value) { + return "[Object EnrichedMarkdownTextMarkdownStyleStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownTextMarkdownStyleStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownTextMd4cFlagsStruct { + bool underline{false}; + bool latexMath{false}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownTextMd4cFlagsStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["underline"] = underline; + result["latexMath"] = latexMath; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownTextMd4cFlagsStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_underline = map.find("underline"); + if (tmp_underline != map.end()) { + fromRawValue(context, tmp_underline->second, result.underline); + } + auto tmp_latexMath = map.find("latexMath"); + if (tmp_latexMath != map.end()) { + fromRawValue(context, tmp_latexMath->second, result.latexMath); + } +} + +static inline std::string toString(const EnrichedMarkdownTextMd4cFlagsStruct &value) { + return "[Object EnrichedMarkdownTextMd4cFlagsStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownTextMd4cFlagsStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownTextContextMenuItemsStruct { + std::string text{}; + std::string icon{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownTextContextMenuItemsStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["text"] = text; + result["icon"] = icon; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownTextContextMenuItemsStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_text = map.find("text"); + if (tmp_text != map.end()) { + fromRawValue(context, tmp_text->second, result.text); + } + auto tmp_icon = map.find("icon"); + if (tmp_icon != map.end()) { + fromRawValue(context, tmp_icon->second, result.icon); + } +} + +static inline std::string toString(const EnrichedMarkdownTextContextMenuItemsStruct &value) { + return "[Object EnrichedMarkdownTextContextMenuItemsStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownTextContextMenuItemsStruct &value) { + return value.toDynamic(); +} +#endif + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, std::vector &result) { + auto items = (std::vector)value; + for (const auto &item : items) { + EnrichedMarkdownTextContextMenuItemsStruct newItem; + fromRawValue(context, item, newItem); + result.emplace_back(newItem); + } +} + +class EnrichedMarkdownTextProps final : public ViewProps { + public: + EnrichedMarkdownTextProps() = default; + EnrichedMarkdownTextProps(const PropsParserContext& context, const EnrichedMarkdownTextProps &sourceProps, const RawProps &rawProps); + +#pragma mark - Props + + std::string markdown{}; + EnrichedMarkdownTextMarkdownStyleStruct markdownStyle{}; + bool enableLinkPreview{true}; + bool selectable{false}; + SharedColor selectionColor{}; + SharedColor selectionHandleColor{}; + EnrichedMarkdownTextMd4cFlagsStruct md4cFlags{}; + bool allowFontScaling{true}; + Float maxFontSizeMultiplier{0.0}; + bool allowTrailingMargin{false}; + bool streamingAnimation{false}; + std::string spoilerOverlay{std::string{"particles"}}; + std::vector contextMenuItems{}; + + #ifdef RN_SERIALIZABLE_STATE + ComponentName getDiffPropsImplementationTarget() const override; + + folly::dynamic getDiffProps(const Props* prevProps) const override; + #endif + + +}; + +} // namespace facebook::react diff --git a/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/ShadowNodes.cpp b/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/ShadowNodes.cpp new file mode 100644 index 00000000..feadde33 --- /dev/null +++ b/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/ShadowNodes.cpp @@ -0,0 +1,17 @@ + +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateShadowNodeCpp.js + */ + +#include "ShadowNodes.h" + +namespace facebook::react { + + + +} // namespace facebook::react diff --git a/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/ShadowNodes.h b/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/ShadowNodes.h new file mode 100644 index 00000000..615dfa65 --- /dev/null +++ b/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/ShadowNodes.h @@ -0,0 +1,23 @@ + +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateShadowNodeH.js + */ + +#pragma once + +#include "EventEmitters.h" +#include "Props.h" +#include "States.h" +#include +#include + +namespace facebook::react { + + + +} // namespace facebook::react diff --git a/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/States.cpp b/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/States.cpp new file mode 100644 index 00000000..1dbb184c --- /dev/null +++ b/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/States.cpp @@ -0,0 +1,16 @@ + +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateStateCpp.js + */ +#include "States.h" + +namespace facebook::react { + + + +} // namespace facebook::react diff --git a/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/States.h b/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/States.h new file mode 100644 index 00000000..2e55bce7 --- /dev/null +++ b/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/States.h @@ -0,0 +1,20 @@ +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateStateH.js + */ +#pragma once + +#include +#ifdef RN_SERIALIZABLE_STATE +#include +#endif + +namespace facebook::react { + + + +} // namespace facebook::react \ No newline at end of file diff --git a/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdown.kt b/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdown.kt index dceb56a7..cac7a6d2 100644 --- a/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdown.kt +++ b/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdown.kt @@ -18,6 +18,7 @@ import com.swmansion.enriched.markdown.utils.common.FeatureFlags import com.swmansion.enriched.markdown.utils.common.MarkdownSegmentRenderer import com.swmansion.enriched.markdown.utils.common.RenderedSegment import com.swmansion.enriched.markdown.utils.common.splitASTIntoSegments +import com.swmansion.enriched.markdown.utils.text.view.applySelectionColors import com.swmansion.enriched.markdown.utils.text.view.emitLinkLongPressEvent import com.swmansion.enriched.markdown.utils.text.view.emitLinkPressEvent import com.swmansion.enriched.markdown.views.BlockSegmentView @@ -54,9 +55,13 @@ class EnrichedMarkdown private var maxFontSizeMultiplier: Float = 0f private var allowTrailingMargin: Boolean = false private var selectable: Boolean = true + private var selectionColor: Int? = null + private var selectionHandleColor: Int? = null private var onLinkPressCallback: ((String) -> Unit)? = null private var onLinkLongPressCallback: ((String) -> Unit)? = null + private var onMentionPressCallback: ((String, String) -> Unit)? = null + private var onCitationPressCallback: ((String, String) -> Unit)? = null private var onTaskListItemPressCallback: ((Int, Boolean, String) -> Unit)? = null private var contextMenuItemTexts: List = emptyList() var onContextMenuItemPressCallback: ((itemText: String, selectedText: String, selectionStart: Int, selectionEnd: Int) -> Unit)? = null @@ -128,6 +133,22 @@ class EnrichedMarkdown } } + fun setSelectionColor(color: Int?) { + selectionColor = color + applySelectionColorsToSegments() + } + + fun setSelectionHandleColor(color: Int?) { + selectionHandleColor = color + applySelectionColorsToSegments() + } + + private fun applySelectionColorsToSegments() { + segmentViews.filterIsInstance().forEach { + it.applySelectionColors(selectionColor, selectionHandleColor) + } + } + fun setOnLinkPressCallback(callback: (String) -> Unit) { onLinkPressCallback = callback } @@ -136,6 +157,14 @@ class EnrichedMarkdown onLinkLongPressCallback = callback } + fun setOnMentionPressCallback(callback: ((url: String, text: String) -> Unit)?) { + onMentionPressCallback = callback + } + + fun setOnCitationPressCallback(callback: ((url: String, text: String) -> Unit)?) { + onCitationPressCallback = callback + } + fun setOnTaskListItemPressCallback(callback: ((taskIndex: Int, checked: Boolean, itemText: String) -> Unit)?) { onTaskListItemPressCallback = callback } @@ -224,6 +253,8 @@ class EnrichedMarkdown justificationMode = android.text.Layout.JUSTIFICATION_MODE_INTER_WORD } lastElementMarginBottom = segment.lastElementMarginBottom + onMentionPressCallback = this@EnrichedMarkdown.onMentionPressCallback + onCitationPressCallback = this@EnrichedMarkdown.onCitationPressCallback applyStyledText(segment.styledText) segment.imageSpans.forEach { it.registerTextView(this) } @@ -234,6 +265,8 @@ class EnrichedMarkdown if (contextMenuItemTexts.isNotEmpty()) { setContextMenuItems(contextMenuItemTexts, ::forwardContextMenuItemPress) } + + applySelectionColors(selectionColor, selectionHandleColor) } private fun createTableView( @@ -244,6 +277,8 @@ class EnrichedMarkdown maxFontSizeMultiplier = this@EnrichedMarkdown.maxFontSizeMultiplier onLinkPress = onLinkPressCallback onLinkLongPress = onLinkLongPressCallback + onMentionPress = onMentionPressCallback + onCitationPress = onCitationPressCallback applyTableNode(segment.node) } diff --git a/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownInternalText.kt b/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownInternalText.kt index 75516569..8952110b 100644 --- a/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownInternalText.kt +++ b/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownInternalText.kt @@ -38,6 +38,9 @@ class EnrichedMarkdownInternalText checkboxTouchHelper.onCheckboxTap = value } + var onMentionPressCallback: ((url: String, text: String) -> Unit)? = null + var onCitationPressCallback: ((url: String, text: String) -> Unit)? = null + override val segmentMarginBottom: Int get() = lastElementMarginBottom.toInt() override var spoilerOverlayDrawer: SpoilerOverlayDrawer? = null @@ -61,9 +64,11 @@ class EnrichedMarkdownInternalText fun applyStyledText(styledText: CharSequence) { text = styledText - if (movementMethod !is LinkLongPressMovementMethod) { - movementMethod = LinkLongPressMovementMethod.createInstance() - } + val method = + (movementMethod as? LinkLongPressMovementMethod) + ?: LinkLongPressMovementMethod.createInstance().also { movementMethod = it } + method.onMentionTap = { url, mentionText -> onMentionPressCallback?.invoke(url, mentionText) } + method.onCitationTap = { url, citationText -> onCitationPressCallback?.invoke(url, citationText) } spoilerOverlayDrawer = SpoilerOverlayDrawer.setupIfNeeded(this, styledText, spoilerOverlayDrawer, spoilerOverlay) accessibilityHelper.invalidateAccessibilityItems() diff --git a/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownManager.kt b/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownManager.kt index 89a31534..34698618 100644 --- a/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownManager.kt +++ b/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownManager.kt @@ -12,9 +12,11 @@ import com.facebook.react.viewmanagers.EnrichedMarkdownManagerDelegate import com.facebook.react.viewmanagers.EnrichedMarkdownManagerInterface import com.facebook.yoga.YogaMeasureMode import com.swmansion.enriched.markdown.spoiler.SpoilerOverlay +import com.swmansion.enriched.markdown.utils.common.emitCitationPress import com.swmansion.enriched.markdown.utils.common.emitContextMenuItemPress import com.swmansion.enriched.markdown.utils.common.emitLinkLongPress import com.swmansion.enriched.markdown.utils.common.emitLinkPress +import com.swmansion.enriched.markdown.utils.common.emitMentionPress import com.swmansion.enriched.markdown.utils.common.emitTaskListItemPress import com.swmansion.enriched.markdown.utils.common.markdownEventTypeConstants import com.swmansion.enriched.markdown.utils.common.parseContextMenuItems @@ -54,6 +56,14 @@ class EnrichedMarkdownManager : emitLinkLongPress(view, url) } + view?.setOnMentionPressCallback { url, text -> + emitMentionPress(view, url, text) + } + + view?.setOnCitationPressCallback { url, text -> + emitCitationPress(view, url, text) + } + view?.setOnTaskListItemPressCallback { taskIndex, checked, itemText -> val newChecked = !checked val updatedMarkdown = TaskListToggleUtils.toggleAtIndex(view.currentMarkdown, taskIndex, newChecked) @@ -80,6 +90,20 @@ class EnrichedMarkdownManager : view?.setIsSelectable(selectable) } + override fun setSelectionColor( + view: EnrichedMarkdown?, + value: Int?, + ) { + view?.setSelectionColor(value) + } + + override fun setSelectionHandleColor( + view: EnrichedMarkdown?, + value: Int?, + ) { + view?.setSelectionHandleColor(value) + } + @ReactProp(name = "md4cFlags") override fun setMd4cFlags( view: EnrichedMarkdown?, diff --git a/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownText.kt b/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownText.kt index aa9614e4..e88f9d90 100644 --- a/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownText.kt +++ b/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownText.kt @@ -23,11 +23,14 @@ import com.swmansion.enriched.markdown.utils.text.TailFadeInAnimator import com.swmansion.enriched.markdown.utils.text.interaction.CheckboxTouchHelper import com.swmansion.enriched.markdown.utils.text.view.LinkLongPressMovementMethod import com.swmansion.enriched.markdown.utils.text.view.applySelectableState +import com.swmansion.enriched.markdown.utils.text.view.applySelectionColors import com.swmansion.enriched.markdown.utils.text.view.cancelJSTouchForCheckboxTap import com.swmansion.enriched.markdown.utils.text.view.cancelJSTouchForLinkTap import com.swmansion.enriched.markdown.utils.text.view.createSelectionActionModeCallback +import com.swmansion.enriched.markdown.utils.text.view.emitCitationPressEvent import com.swmansion.enriched.markdown.utils.text.view.emitLinkLongPressEvent import com.swmansion.enriched.markdown.utils.text.view.emitLinkPressEvent +import com.swmansion.enriched.markdown.utils.text.view.emitMentionPressEvent import com.swmansion.enriched.markdown.utils.text.view.setupAsMarkdownTextView import java.util.concurrent.Executors @@ -81,6 +84,9 @@ class EnrichedMarkdownText private set var spoilerOverlay: SpoilerOverlay = SpoilerOverlay.PARTICLES + private var selectionColor: Int? = null + private var selectionHandleColor: Int? = null + init { setupAsMarkdownTextView() customSelectionActionModeCallback = @@ -228,9 +234,11 @@ class EnrichedMarkdownText text = styledText - if (movementMethod !is LinkLongPressMovementMethod) { - movementMethod = LinkLongPressMovementMethod.createInstance() - } + val method = + (movementMethod as? LinkLongPressMovementMethod) + ?: LinkLongPressMovementMethod.createInstance().also { movementMethod = it } + method.onMentionTap = { url, mentionText -> emitOnMentionPress(url, mentionText) } + method.onCitationTap = { url, citationText -> emitOnCitationPress(url, citationText) } renderer.getCollectedImageSpans().forEach { span -> span.registerTextView(this) @@ -248,6 +256,8 @@ class EnrichedMarkdownText fadeAnimator?.animate(tailStart, styledText.length) previousTextLength = styledText.length } + + applySelectionColors(selectionColor, selectionHandleColor) } fun setContextMenuItems(items: List) { @@ -258,6 +268,16 @@ class EnrichedMarkdownText applySelectableState(selectable) } + fun setSelectionColor(color: Int?) { + selectionColor = color + applySelectionColors(selectionColor, selectionHandleColor) + } + + fun setSelectionHandleColor(color: Int?) { + selectionHandleColor = color + applySelectionColors(selectionColor, selectionHandleColor) + } + fun emitOnLinkPress(url: String) { emitLinkPressEvent(url) } @@ -266,6 +286,20 @@ class EnrichedMarkdownText emitLinkLongPressEvent(url) } + fun emitOnMentionPress( + url: String, + text: String, + ) { + emitMentionPressEvent(url, text) + } + + fun emitOnCitationPress( + url: String, + text: String, + ) { + emitCitationPressEvent(url, text) + } + fun setOnLinkPressCallback(callback: (String) -> Unit) { onLinkPressCallback = callback } diff --git a/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownTextManager.kt b/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownTextManager.kt index 4cce5323..ed860bc8 100644 --- a/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownTextManager.kt +++ b/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownTextManager.kt @@ -100,6 +100,20 @@ class EnrichedMarkdownTextManager : view?.setIsSelectable(selectable) } + override fun setSelectionColor( + view: EnrichedMarkdownText?, + value: Int?, + ) { + view?.setSelectionColor(value) + } + + override fun setSelectionHandleColor( + view: EnrichedMarkdownText?, + value: Int?, + ) { + view?.setSelectionHandleColor(value) + } + @ReactProp(name = "md4cFlags") override fun setMd4cFlags( view: EnrichedMarkdownText?, diff --git a/android/src/main/java/com/swmansion/enriched/markdown/events/CitationPressEvent.kt b/android/src/main/java/com/swmansion/enriched/markdown/events/CitationPressEvent.kt new file mode 100644 index 00000000..b41d4fb8 --- /dev/null +++ b/android/src/main/java/com/swmansion/enriched/markdown/events/CitationPressEvent.kt @@ -0,0 +1,25 @@ +package com.swmansion.enriched.markdown.events + +import com.facebook.react.bridge.Arguments +import com.facebook.react.bridge.WritableMap +import com.facebook.react.uimanager.events.Event + +class CitationPressEvent( + surfaceId: Int, + viewId: Int, + private val url: String, + private val text: String, +) : Event(surfaceId, viewId) { + override fun getEventName(): String = EVENT_NAME + + override fun getEventData(): WritableMap { + val eventData: WritableMap = Arguments.createMap() + eventData.putString("url", url) + eventData.putString("text", text) + return eventData + } + + companion object { + const val EVENT_NAME: String = "onCitationPress" + } +} diff --git a/android/src/main/java/com/swmansion/enriched/markdown/events/MentionPressEvent.kt b/android/src/main/java/com/swmansion/enriched/markdown/events/MentionPressEvent.kt new file mode 100644 index 00000000..211d608e --- /dev/null +++ b/android/src/main/java/com/swmansion/enriched/markdown/events/MentionPressEvent.kt @@ -0,0 +1,25 @@ +package com.swmansion.enriched.markdown.events + +import com.facebook.react.bridge.Arguments +import com.facebook.react.bridge.WritableMap +import com.facebook.react.uimanager.events.Event + +class MentionPressEvent( + surfaceId: Int, + viewId: Int, + private val url: String, + private val text: String, +) : Event(surfaceId, viewId) { + override fun getEventName(): String = EVENT_NAME + + override fun getEventData(): WritableMap { + val eventData: WritableMap = Arguments.createMap() + eventData.putString("url", url) + eventData.putString("text", text) + return eventData + } + + companion object { + const val EVENT_NAME: String = "onMentionPress" + } +} diff --git a/android/src/main/java/com/swmansion/enriched/markdown/renderer/BlockquoteRenderer.kt b/android/src/main/java/com/swmansion/enriched/markdown/renderer/BlockquoteRenderer.kt index 5389284f..4757f539 100644 --- a/android/src/main/java/com/swmansion/enriched/markdown/renderer/BlockquoteRenderer.kt +++ b/android/src/main/java/com/swmansion/enriched/markdown/renderer/BlockquoteRenderer.kt @@ -3,6 +3,7 @@ package com.swmansion.enriched.markdown.renderer import android.text.SpannableStringBuilder import com.swmansion.enriched.markdown.parser.MarkdownASTNode import com.swmansion.enriched.markdown.spans.BlockquoteSpan +import com.swmansion.enriched.markdown.utils.text.span.SPAN_FLAGS_CONTAINER_BACKGROUND import com.swmansion.enriched.markdown.utils.text.span.SPAN_FLAGS_EXCLUSIVE_EXCLUSIVE import com.swmansion.enriched.markdown.utils.text.span.applyMarginBottom import com.swmansion.enriched.markdown.utils.text.span.applyMarginTop @@ -45,12 +46,14 @@ class BlockquoteRenderer( .map { builder.getSpanStart(it) to builder.getSpanEnd(it) } .sortedBy { it.first } - // The Accent Bar Span covers the full range for visual continuity + // The accent bar span covers the full range for visual continuity. + // SPAN_FLAGS_CONTAINER_BACKGROUND keeps the blockquote fill under any + // inline chip/pill backgrounds on the same line. builder.setSpan( BlockquoteSpan(style, depth, factory.context, factory.styleCache), start, end, - SPAN_FLAGS_EXCLUSIVE_EXCLUSIVE, + SPAN_FLAGS_CONTAINER_BACKGROUND, ) // Apply styling only to segments that are NOT nested quotes diff --git a/android/src/main/java/com/swmansion/enriched/markdown/renderer/LinkRenderer.kt b/android/src/main/java/com/swmansion/enriched/markdown/renderer/LinkRenderer.kt index 7beb976e..81c2179e 100644 --- a/android/src/main/java/com/swmansion/enriched/markdown/renderer/LinkRenderer.kt +++ b/android/src/main/java/com/swmansion/enriched/markdown/renderer/LinkRenderer.kt @@ -2,12 +2,20 @@ package com.swmansion.enriched.markdown.renderer import android.text.SpannableStringBuilder import com.swmansion.enriched.markdown.parser.MarkdownASTNode +import com.swmansion.enriched.markdown.spans.CitationSpan import com.swmansion.enriched.markdown.spans.LinkSpan +import com.swmansion.enriched.markdown.spans.MentionSpacerSpan +import com.swmansion.enriched.markdown.spans.MentionSpan import com.swmansion.enriched.markdown.utils.text.span.SPAN_FLAGS_EXCLUSIVE_EXCLUSIVE class LinkRenderer( private val config: RendererConfig, ) : NodeRenderer { + companion object { + private const val MENTION_SCHEME = "mention://" + private const val CITATION_SCHEME = "citation://" + } + override fun render( node: MarkdownASTNode, builder: SpannableStringBuilder, @@ -17,6 +25,43 @@ class LinkRenderer( ) { val url = node.getAttribute("url") ?: return + when { + url.startsWith(MENTION_SCHEME) -> { + renderMention( + url.removePrefix(MENTION_SCHEME), + node, + builder, + onLinkPress, + onLinkLongPress, + factory, + ) + } + + url.startsWith(CITATION_SCHEME) -> { + renderCitation( + url.removePrefix(CITATION_SCHEME), + node, + builder, + onLinkPress, + onLinkLongPress, + factory, + ) + } + + else -> { + renderLink(url, node, builder, onLinkPress, onLinkLongPress, factory) + } + } + } + + private fun renderLink( + url: String, + node: MarkdownASTNode, + builder: SpannableStringBuilder, + onLinkPress: ((String) -> Unit)?, + onLinkLongPress: ((String) -> Unit)?, + factory: RendererFactory, + ) { factory.renderWithSpan(builder, { factory.renderChildren(node, builder, onLinkPress, onLinkLongPress) }) { start, end, blockStyle -> builder.setSpan( LinkSpan(url, onLinkPress, onLinkLongPress, factory.styleCache, blockStyle, factory.context), @@ -26,4 +71,73 @@ class LinkRenderer( ) } } + + private fun renderMention( + url: String, + node: MarkdownASTNode, + builder: SpannableStringBuilder, + onLinkPress: ((String) -> Unit)?, + onLinkLongPress: ((String) -> Unit)?, + factory: RendererFactory, + ) { + // Render children into a throwaway buffer to derive the plain display + // label (any inline formatting inside the mention collapses to text). + val labelBuffer = SpannableStringBuilder() + factory.renderChildren(node, labelBuffer, onLinkPress, onLinkLongPress) + val displayText = labelBuffer.toString() + if (displayText.isEmpty()) return + + // Append the displayText as real characters so copy/paste, selection, and + // accessibility traversal all see the mention as normal text. The pill + // background is painted by the MentionSpan's LineBackgroundSpan pass. + val start = builder.length + builder.append(displayText) + val end = builder.length + + val span = + MentionSpan( + url = url, + displayText = displayText, + mentionStyle = factory.styleCache.mentionStyle, + mentionTypeface = factory.styleCache.mentionTypeface, + ) + builder.setSpan(span, start, end, SPAN_FLAGS_EXCLUSIVE_EXCLUSIVE) + + // The pill background extends `paddingHorizontal` past the glyph run on + // each side, but the underlying inline text doesn't reserve any advance + // for that visual overhang. Without extra spacing, two adjacent mention + // pills (separated only by a space in the source markdown) visually + // overlap. Appending a zero-width sentinel char with a MentionSpacerSpan + // reserves `paddingHorizontal * 2` of advance after each mention — the + // Android-side equivalent of the NSKern we apply on iOS. + val mentionStyle = factory.styleCache.mentionStyle + if (mentionStyle.paddingHorizontal > 0f) { + val spacerStart = builder.length + builder.append("\u200B") // zero-width space + builder.setSpan( + MentionSpacerSpan(mentionStyle.paddingHorizontal * 2f), + spacerStart, + builder.length, + SPAN_FLAGS_EXCLUSIVE_EXCLUSIVE, + ) + } + } + + private fun renderCitation( + url: String, + node: MarkdownASTNode, + builder: SpannableStringBuilder, + onLinkPress: ((String) -> Unit)?, + onLinkLongPress: ((String) -> Unit)?, + factory: RendererFactory, + ) { + val start = builder.length + factory.renderChildren(node, builder, onLinkPress, onLinkLongPress) + val end = builder.length + if (end <= start) return + + val displayText = builder.subSequence(start, end).toString() + val span = CitationSpan(url = url, displayText = displayText, citationStyle = factory.styleCache.citationStyle) + builder.setSpan(span, start, end, SPAN_FLAGS_EXCLUSIVE_EXCLUSIVE) + } } diff --git a/android/src/main/java/com/swmansion/enriched/markdown/renderer/SpanStyleCache.kt b/android/src/main/java/com/swmansion/enriched/markdown/renderer/SpanStyleCache.kt index 8379c63a..7cc6e2aa 100644 --- a/android/src/main/java/com/swmansion/enriched/markdown/renderer/SpanStyleCache.kt +++ b/android/src/main/java/com/swmansion/enriched/markdown/renderer/SpanStyleCache.kt @@ -1,6 +1,8 @@ package com.swmansion.enriched.markdown.renderer import android.graphics.Typeface +import com.swmansion.enriched.markdown.styles.CitationStyle +import com.swmansion.enriched.markdown.styles.MentionStyle import com.swmansion.enriched.markdown.styles.StyleConfig /** Shared style cache for spans to avoid redundant calculations. */ @@ -27,6 +29,9 @@ class SpanStyleCache( val spoilerParticleDensity: Float = style.spoilerStyle.particleDensity val spoilerParticleSpeed: Float = style.spoilerStyle.particleSpeed val spoilerSolidBorderRadius: Float = style.spoilerStyle.solidBorderRadius + val mentionStyle: MentionStyle = style.mentionStyle + val mentionTypeface: Typeface? = style.mentionTypeface + val citationStyle: CitationStyle = style.citationStyle private fun buildColorsToPreserve(style: StyleConfig): IntArray { val paragraphColor = style.paragraphStyle.color @@ -48,6 +53,19 @@ class SpanStyleCache( style.taskListStyle.checkedTextColor .takeIf { it != 0 } ?.let { add(it) } + // Inline chip colors (mention / citation). Container spans like + // BaseListSpan and BlockquoteSpan overwrite text color via + // `applyColorPreserving(blockColor, colorsToPreserve)`. Including the + // chip colors here ensures the mention/citation foreground set by + // MentionSpan / CitationSpan survives that overwrite — otherwise the + // chip text falls back to the surrounding block color inside lists or + // blockquotes. + style.mentionStyle.color + .takeIf { it != 0 && it != paragraphColor } + ?.let { add(it) } + style.citationStyle.color + .takeIf { it != 0 && it != paragraphColor } + ?.let { add(it) } }.toIntArray() } diff --git a/android/src/main/java/com/swmansion/enriched/markdown/spans/BlockquoteSpan.kt b/android/src/main/java/com/swmansion/enriched/markdown/spans/BlockquoteSpan.kt index f8230f6e..2808a4bd 100644 --- a/android/src/main/java/com/swmansion/enriched/markdown/spans/BlockquoteSpan.kt +++ b/android/src/main/java/com/swmansion/enriched/markdown/spans/BlockquoteSpan.kt @@ -10,6 +10,7 @@ import android.text.Layout import android.text.Spanned import android.text.TextPaint import android.text.style.LeadingMarginSpan +import android.text.style.LineBackgroundSpan import android.text.style.MetricAffectingSpan import com.swmansion.enriched.markdown.renderer.BlockStyle import com.swmansion.enriched.markdown.renderer.SpanStyleCache @@ -23,7 +24,8 @@ class BlockquoteSpan( private val context: Context, private val styleCache: SpanStyleCache, ) : MetricAffectingSpan(), - LeadingMarginSpan { + LeadingMarginSpan, + LineBackgroundSpan { private val levelSpacing: Float = blockquoteStyle.borderWidth + blockquoteStyle.gapWidth private val blockStyle = BlockStyle( @@ -60,8 +62,6 @@ class BlockquoteSpan( // Essential check from original: only the deepest span draws to prevent over-rendering background if (shouldSkipDrawing(text, start)) return - drawBackground(c, top, bottom, layout) - val borderPaint = configureBorderPaint() val borderTop = top.toFloat() val borderBottom = bottom.toFloat() @@ -73,6 +73,23 @@ class BlockquoteSpan( } } + override fun drawBackground( + canvas: Canvas, + paint: Paint, + left: Int, + right: Int, + top: Int, + baseline: Int, + bottom: Int, + text: CharSequence, + start: Int, + end: Int, + lineNum: Int, + ) { + if (shouldSkipDrawing(text, start)) return + drawBackground(canvas, left, top, bottom, right) + } + @SuppressLint("WrongConstant") // Result of mask is always valid: 0, 1, 2, or 3 private fun applyTextStyle(tp: TextPaint) { tp.textSize = blockStyle.fontSize @@ -123,12 +140,13 @@ class BlockquoteSpan( private fun drawBackground( c: Canvas, + left: Int, top: Int, bottom: Int, - layout: Layout?, + right: Int, ) { val bgColor = blockquoteStyle.backgroundColor?.takeIf { it != Color.TRANSPARENT } ?: return val backgroundPaint = configureBackgroundPaint(bgColor) - c.drawRect(0f, top.toFloat(), layout?.width?.toFloat() ?: 0f, bottom.toFloat(), backgroundPaint) + c.drawRect(left.toFloat(), top.toFloat(), right.toFloat(), bottom.toFloat(), backgroundPaint) } } diff --git a/android/src/main/java/com/swmansion/enriched/markdown/spans/CitationSpan.kt b/android/src/main/java/com/swmansion/enriched/markdown/spans/CitationSpan.kt new file mode 100644 index 00000000..01e0b3d4 --- /dev/null +++ b/android/src/main/java/com/swmansion/enriched/markdown/spans/CitationSpan.kt @@ -0,0 +1,145 @@ +package com.swmansion.enriched.markdown.spans + +import android.graphics.Canvas +import android.graphics.Paint +import android.graphics.RectF +import android.graphics.Typeface +import android.text.style.ReplacementSpan +import com.swmansion.enriched.markdown.styles.CitationStyle + +/** + * Inline citation marker. Renders atomically (via [ReplacementSpan]) so the + * renderer can apply: + * - font-size multiplier (smaller than surrounding text) + * - explicit baselineOffsetPx (parity with iOS `NSBaselineOffsetAttributeName`) + * - optional padded background (chip look when `backgroundColor` is set) + * + * Padding always contributes to the advance width / line height so adjacent + * text and wrapping behave correctly even when no background is drawn. + */ +class CitationSpan( + val url: String, + val displayText: String, + private val citationStyle: CitationStyle, +) : ReplacementSpan() { + private val fillPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply { style = Paint.Style.FILL } + private val strokePaint = Paint(Paint.ANTI_ALIAS_FLAG).apply { style = Paint.Style.STROKE } + private val textPaint = Paint(Paint.ANTI_ALIAS_FLAG or Paint.SUBPIXEL_TEXT_FLAG) + + private fun configureTextPaint(basePaint: Paint) { + textPaint.set(basePaint) + val multiplier = citationStyle.fontSizeMultiplier + if (multiplier > 0f) { + textPaint.textSize = basePaint.textSize * multiplier + } + textPaint.color = citationStyle.color + textPaint.isUnderlineText = citationStyle.underline + if (citationStyle.fontWeight.isNotEmpty()) { + val base = textPaint.typeface ?: Typeface.DEFAULT + val weightStyle = + when (citationStyle.fontWeight.lowercase()) { + "bold", "700", "800", "900" -> Typeface.BOLD + else -> Typeface.NORMAL + } + textPaint.typeface = Typeface.create(base, weightStyle) + } + } + + private fun textWidth(): Float = textPaint.measureText(displayText) + + override fun getSize( + paint: Paint, + text: CharSequence?, + start: Int, + end: Int, + fm: Paint.FontMetricsInt?, + ): Int { + configureTextPaint(paint) + + val totalWidth = textWidth() + citationStyle.paddingHorizontal * 2f + + if (fm != null) { + // Base metrics come from the surrounding paragraph so the citation + // sits on the same line as the host text. Padding is added to top/bottom + // so a visible background extends past the glyph bounds. + val base = paint.fontMetricsInt + val offset = resolveBaselineOffset() + val verticalInset = citationStyle.paddingVertical.toInt() + fm.ascent = base.ascent - verticalInset - offset.toInt() + fm.top = base.top - verticalInset - offset.toInt() + fm.descent = base.descent + verticalInset + fm.bottom = base.bottom + verticalInset + fm.leading = base.leading + } + + return totalWidth.toInt() + 1 + } + + override fun draw( + canvas: Canvas, + text: CharSequence, + start: Int, + end: Int, + x: Float, + top: Int, + y: Int, + bottom: Int, + paint: Paint, + ) { + configureTextPaint(paint) + + val offset = resolveBaselineOffset() + val paddingH = citationStyle.paddingHorizontal + val paddingV = citationStyle.paddingVertical + + val textW = textWidth() + val chipWidth = textW + paddingH * 2f + val metrics = textPaint.fontMetricsInt + val textAscent = metrics.ascent.toFloat() + val textDescent = metrics.descent.toFloat() + + // Baseline for the citation glyph, raised above the host baseline. + val glyphBaseline = y - offset + + // Background rectangle bounds the shifted glyph plus vertical padding. + val bgTop = glyphBaseline + textAscent - paddingV + val bgBottom = glyphBaseline + textDescent + paddingV + + val maxRadius = minOf((bgBottom - bgTop) / 2f, chipWidth / 2f) + val radius = minOf(citationStyle.borderRadius, maxRadius) + val chipRect = RectF(x, bgTop, x + chipWidth, bgBottom) + + if (citationStyle.backgroundColor != null && citationStyle.backgroundColor != 0) { + fillPaint.color = citationStyle.backgroundColor + canvas.drawRoundRect(chipRect, radius, radius, fillPaint) + } + + if (citationStyle.borderColor != null && citationStyle.borderColor != 0 && citationStyle.borderWidth > 0f) { + strokePaint.color = citationStyle.borderColor + strokePaint.strokeWidth = citationStyle.borderWidth + // Inset the stroke by half its width so the border stays inside the chip + // rect (matches the iOS UIBezierPath stroke). + val halfStroke = citationStyle.borderWidth / 2f + val borderRect = + RectF( + chipRect.left + halfStroke, + chipRect.top + halfStroke, + chipRect.right - halfStroke, + chipRect.bottom - halfStroke, + ) + val borderRadius = minOf(radius, minOf(borderRect.width(), borderRect.height()) / 2f) + canvas.drawRoundRect(borderRect, borderRadius, borderRadius, strokePaint) + } + + canvas.drawText(displayText, x + paddingH, glyphBaseline, textPaint) + } + + private fun resolveBaselineOffset(): Float = + if (citationStyle.baselineOffsetPx != 0f) { + citationStyle.baselineOffsetPx + } else { + // Fallback: raise the smaller glyph so its mid-line sits near the + // cap-height of the surrounding text. + -textPaint.ascent() * 0.5f + } +} diff --git a/android/src/main/java/com/swmansion/enriched/markdown/spans/MentionSpacerSpan.kt b/android/src/main/java/com/swmansion/enriched/markdown/spans/MentionSpacerSpan.kt new file mode 100644 index 00000000..83b6c1b3 --- /dev/null +++ b/android/src/main/java/com/swmansion/enriched/markdown/spans/MentionSpacerSpan.kt @@ -0,0 +1,55 @@ +package com.swmansion.enriched.markdown.spans + +import android.graphics.Canvas +import android.graphics.Paint +import android.text.style.ReplacementSpan + +/** + * Reserves a fixed horizontal advance on a single sentinel character + * (typically ZWSP) appended after an inline mention. This mirrors the trailing + * NSKern iOS uses to space consecutive mention pills apart — the mention's + * own `LineBackgroundSpan` draws its pill extending `paddingHorizontal` past + * the glyph run on both sides, and without reserved advance here the pills of + * two adjacent mentions would visually overlap. + * + * The span draws nothing, so the sentinel character is invisible; it only + * affects layout. + */ +class MentionSpacerSpan( + private val widthPx: Float, +) : ReplacementSpan() { + override fun getSize( + paint: Paint, + text: CharSequence?, + start: Int, + end: Int, + fm: Paint.FontMetricsInt?, + ): Int { + if (fm != null) { + // Match the surrounding line metrics so the sentinel doesn't affect + // line height. + val metrics = paint.fontMetricsInt + fm.ascent = metrics.ascent + fm.top = metrics.top + fm.descent = metrics.descent + fm.bottom = metrics.bottom + fm.leading = metrics.leading + } + return widthPx.toInt().coerceAtLeast(0) + } + + override fun draw( + canvas: Canvas, + text: CharSequence, + start: Int, + end: Int, + x: Float, + top: Int, + y: Int, + bottom: Int, + paint: Paint, + ) { + // Intentionally no-op — the sentinel is invisible and only reserves + // advance width so adjacent mention pills don't visually overlap. + } +} diff --git a/android/src/main/java/com/swmansion/enriched/markdown/spans/MentionSpan.kt b/android/src/main/java/com/swmansion/enriched/markdown/spans/MentionSpan.kt new file mode 100644 index 00000000..a0efb4fb --- /dev/null +++ b/android/src/main/java/com/swmansion/enriched/markdown/spans/MentionSpan.kt @@ -0,0 +1,157 @@ +package com.swmansion.enriched.markdown.spans + +import android.graphics.Canvas +import android.graphics.Paint +import android.graphics.RectF +import android.graphics.Typeface +import android.text.Spanned +import android.text.StaticLayout +import android.text.TextPaint +import android.text.style.LineBackgroundSpan +import android.text.style.MetricAffectingSpan +import com.swmansion.enriched.markdown.styles.MentionStyle +import kotlin.math.max +import kotlin.math.min + +/** + * Styles and paints the pill "chip" behind an inline mention. The mention + * text itself lives in the underlying Spannable as real characters, so copy, + * paste, selection, and accessibility all behave like ordinary text — the + * pill appearance is produced by this span's [LineBackgroundSpan.drawBackground] + * pass. + * + * The span exposes [url] for tap dispatching and an [isPressed] flag the tap + * handler can toggle to drive the pressedOpacity feedback. + */ +class MentionSpan( + val url: String, + val displayText: String, + private val mentionStyle: MentionStyle, + private val mentionTypeface: Typeface?, +) : MetricAffectingSpan(), + LineBackgroundSpan { + @Volatile + var isPressed: Boolean = false + + private val fillPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply { style = Paint.Style.FILL } + private val strokePaint = + Paint(Paint.ANTI_ALIAS_FLAG).apply { + style = Paint.Style.STROKE + } + private val rect = RectF() + + override fun updateMeasureState(textPaint: TextPaint) { + applyTextStyling(textPaint) + } + + override fun updateDrawState(tp: TextPaint) { + applyTextStyling(tp) + tp.color = mentionStyle.color + } + + private fun applyTextStyling(paint: TextPaint) { + if (mentionStyle.fontSize > 0f) { + paint.textSize = mentionStyle.fontSize + } + if (mentionTypeface != null) { + paint.typeface = mentionTypeface + } else if (mentionStyle.fontWeight.isNotEmpty()) { + val base = paint.typeface ?: Typeface.DEFAULT + val weightStyle = + when (mentionStyle.fontWeight.lowercase()) { + "bold", "700", "800", "900" -> Typeface.BOLD + else -> Typeface.NORMAL + } + paint.typeface = Typeface.create(base, weightStyle) + } + } + + override fun drawBackground( + canvas: Canvas, + paint: Paint, + left: Int, + right: Int, + top: Int, + baseline: Int, + bottom: Int, + text: CharSequence, + start: Int, + end: Int, + lineNum: Int, + ) { + if (text !is Spanned) return + val spanStart = text.getSpanStart(this) + val spanEnd = text.getSpanEnd(this) + if (spanStart < 0 || spanEnd <= spanStart) return + + // Only paint on the line segment(s) the span intersects with. + val drawStart = max(spanStart, start) + val drawEnd = min(spanEnd, end) + if (drawStart >= drawEnd) return + + val opacity = if (isPressed) mentionStyle.pressedOpacity.coerceIn(0f, 1f) else 1f + + val textPaint = (paint as? TextPaint) ?: TextPaint(paint).apply { set(paint) } + // LineBackgroundSpan is invoked before the glyphs are drawn, so the paint + // hasn't been run through updateDrawState yet; apply mention-specific + // styling locally so measurements here match the rendered text exactly. + val localPaint = TextPaint(textPaint) + applyTextStyling(localPaint) + + val startOffset = horizontalOffset(text, start, end, drawStart, localPaint) + val endOffset = horizontalOffset(text, start, end, drawEnd, localPaint) + val paddingH = mentionStyle.paddingHorizontal + val paddingV = mentionStyle.paddingVertical + + val pillLeft = left + min(startOffset, endOffset) - paddingH + val pillRight = left + max(startOffset, endOffset) + paddingH + // Derive vertical extent from the mention's own font metrics (not the + // line's `top`/`bottom`) so the pill hugs the mention text. Using the + // line bounds would stretch the pill to the paragraph's lineHeight, + // which is visibly taller than the glyph when lineHeight > natural + // font height (or when anything else on the line has bigger metrics). + val fm = localPaint.fontMetrics + // ascent is negative (above baseline), descent is positive (below). + val pillTop = baseline + fm.ascent - paddingV + val pillBottom = baseline + fm.descent + paddingV + if (pillRight <= pillLeft || pillBottom <= pillTop) return + + rect.set(pillLeft, pillTop, pillRight, pillBottom) + + val radius = + min( + mentionStyle.borderRadius, + min(rect.width(), rect.height()) / 2f, + ) + + fillPaint.color = mentionStyle.backgroundColor + fillPaint.alpha = + ((fillPaint.color ushr 24) and 0xFF).let { baseAlpha -> + (baseAlpha * opacity).toInt().coerceIn(0, 255) + } + canvas.drawRoundRect(rect, radius, radius, fillPaint) + + if (mentionStyle.borderWidth > 0f) { + strokePaint.strokeWidth = mentionStyle.borderWidth + strokePaint.color = mentionStyle.borderColor + strokePaint.alpha = + ((strokePaint.color ushr 24) and 0xFF).let { baseAlpha -> + (baseAlpha * opacity).toInt().coerceIn(0, 255) + } + canvas.drawRoundRect(rect, radius, radius, strokePaint) + } + } + + private fun horizontalOffset( + text: CharSequence, + lineStart: Int, + lineEnd: Int, + index: Int, + paint: TextPaint, + ): Float { + if (index <= lineStart) return 0f + val lineText = text.subSequence(lineStart, lineEnd) + val layout = StaticLayout.Builder.obtain(lineText, 0, lineText.length, paint, Int.MAX_VALUE / 2).build() + return layout.getPrimaryHorizontal(index - lineStart) + } +} diff --git a/android/src/main/java/com/swmansion/enriched/markdown/styles/CitationStyle.kt b/android/src/main/java/com/swmansion/enriched/markdown/styles/CitationStyle.kt new file mode 100644 index 00000000..8d8f3325 --- /dev/null +++ b/android/src/main/java/com/swmansion/enriched/markdown/styles/CitationStyle.kt @@ -0,0 +1,50 @@ +package com.swmansion.enriched.markdown.styles + +import com.facebook.react.bridge.ReadableMap + +data class CitationStyle( + val color: Int, + val fontSizeMultiplier: Float, + val baselineOffsetPx: Float, + val fontWeight: String, + val underline: Boolean, + val backgroundColor: Int?, + val paddingHorizontal: Float, + val paddingVertical: Float, + val borderColor: Int?, + val borderWidth: Float, + val borderRadius: Float, +) { + companion object { + fun fromReadableMap( + map: ReadableMap, + parser: StyleParser, + ): CitationStyle { + val color = parser.parseColor(map, "color") + val fontSizeMultiplier = parser.parseOptionalDouble(map, "fontSizeMultiplier", 0.7).toFloat() + val baselineOffsetPx = parser.toPixelFromDIP(parser.parseOptionalDouble(map, "baselineOffsetPx").toFloat()) + val fontWeight = parser.parseString(map, "fontWeight") + val underline = parser.parseBoolean(map, "underline", false) + val backgroundColor = parser.parseOptionalColor(map, "backgroundColor") + val paddingHorizontal = parser.toPixelFromDIP(parser.parseOptionalDouble(map, "paddingHorizontal").toFloat()) + val paddingVertical = parser.toPixelFromDIP(parser.parseOptionalDouble(map, "paddingVertical").toFloat()) + val borderColor = parser.parseOptionalColor(map, "borderColor") + val borderWidth = parser.toPixelFromDIP(parser.parseOptionalDouble(map, "borderWidth").toFloat()) + val borderRadius = parser.toPixelFromDIP(parser.parseOptionalDouble(map, "borderRadius", 999.0).toFloat()) + + return CitationStyle( + color = color, + fontSizeMultiplier = if (fontSizeMultiplier > 0) fontSizeMultiplier else 0.7f, + baselineOffsetPx = baselineOffsetPx, + fontWeight = fontWeight, + underline = underline, + backgroundColor = backgroundColor, + paddingHorizontal = paddingHorizontal, + paddingVertical = paddingVertical, + borderColor = borderColor, + borderWidth = borderWidth, + borderRadius = borderRadius, + ) + } + } +} diff --git a/android/src/main/java/com/swmansion/enriched/markdown/styles/MentionStyle.kt b/android/src/main/java/com/swmansion/enriched/markdown/styles/MentionStyle.kt new file mode 100644 index 00000000..81dbc6a1 --- /dev/null +++ b/android/src/main/java/com/swmansion/enriched/markdown/styles/MentionStyle.kt @@ -0,0 +1,50 @@ +package com.swmansion.enriched.markdown.styles + +import com.facebook.react.bridge.ReadableMap + +data class MentionStyle( + val color: Int, + val backgroundColor: Int, + val borderColor: Int, + val borderWidth: Float, + val borderRadius: Float, + val paddingHorizontal: Float, + val paddingVertical: Float, + val fontFamily: String, + val fontWeight: String, + val fontSize: Float, + val pressedOpacity: Float, +) { + companion object { + fun fromReadableMap( + map: ReadableMap, + parser: StyleParser, + ): MentionStyle { + val color = parser.parseColor(map, "color") + val backgroundColor = parser.parseColor(map, "backgroundColor") + val borderColor = parser.parseColor(map, "borderColor") + val borderWidth = parser.toPixelFromDIP(parser.parseOptionalDouble(map, "borderWidth").toFloat()) + val borderRadius = parser.toPixelFromDIP(parser.parseOptionalDouble(map, "borderRadius").toFloat()) + val paddingHorizontal = parser.toPixelFromDIP(parser.parseOptionalDouble(map, "paddingHorizontal").toFloat()) + val paddingVertical = parser.toPixelFromDIP(parser.parseOptionalDouble(map, "paddingVertical").toFloat()) + val fontFamily = parser.parseString(map, "fontFamily") + val fontWeight = parser.parseString(map, "fontWeight") + val fontSize = parser.toPixelFromSP(parser.parseOptionalDouble(map, "fontSize").toFloat()) + val pressedOpacity = parser.parseOptionalDouble(map, "pressedOpacity", 0.6).toFloat() + + return MentionStyle( + color = color, + backgroundColor = backgroundColor, + borderColor = borderColor, + borderWidth = borderWidth, + borderRadius = borderRadius, + paddingHorizontal = paddingHorizontal, + paddingVertical = paddingVertical, + fontFamily = fontFamily, + fontWeight = fontWeight, + fontSize = fontSize, + pressedOpacity = pressedOpacity.coerceIn(0f, 1f), + ) + } + } +} diff --git a/android/src/main/java/com/swmansion/enriched/markdown/styles/StyleConfig.kt b/android/src/main/java/com/swmansion/enriched/markdown/styles/StyleConfig.kt index a851ac9a..27705be6 100644 --- a/android/src/main/java/com/swmansion/enriched/markdown/styles/StyleConfig.kt +++ b/android/src/main/java/com/swmansion/enriched/markdown/styles/StyleConfig.kt @@ -234,6 +234,32 @@ class StyleConfig( SpoilerStyle.fromReadableMap(map, styleParser) } + val mentionStyle: MentionStyle by lazy { + val map = + requireNotNull(style.getMap("mention")) { + "Mention style not found. JS should always provide defaults." + } + MentionStyle.fromReadableMap(map, styleParser) + } + + val citationStyle: CitationStyle by lazy { + val map = + requireNotNull(style.getMap("citation")) { + "Citation style not found. JS should always provide defaults." + } + CitationStyle.fromReadableMap(map, styleParser) + } + + val mentionTypeface: Typeface? by lazy { + val family = mentionStyle.fontFamily.takeIf { it.isNotEmpty() } + val weight = parseFontWeight(mentionStyle.fontWeight) + if (family != null) { + applyStyles(null, ReactConstants.UNSET, weight, family, assets) + } else { + null + } + } + val tableTypeface: Typeface? by lazy { val fontFamily = tableStyle.fontFamily.takeIf { it.isNotEmpty() } val fontWeight = parseFontWeight(tableStyle.fontWeight) @@ -297,7 +323,9 @@ class StyleConfig( taskListStyle == other.taskListStyle && mathStyle == other.mathStyle && inlineMathStyle == other.inlineMathStyle && - spoilerStyle == other.spoilerStyle + spoilerStyle == other.spoilerStyle && + mentionStyle == other.mentionStyle && + citationStyle == other.citationStyle } override fun hashCode(): Int { @@ -320,6 +348,8 @@ class StyleConfig( result = 31 * result + mathStyle.hashCode() result = 31 * result + inlineMathStyle.hashCode() result = 31 * result + spoilerStyle.hashCode() + result = 31 * result + mentionStyle.hashCode() + result = 31 * result + citationStyle.hashCode() return result } } diff --git a/android/src/main/java/com/swmansion/enriched/markdown/utils/common/MarkdownViewManagerUtils.kt b/android/src/main/java/com/swmansion/enriched/markdown/utils/common/MarkdownViewManagerUtils.kt index 9f3152da..6fb88b7e 100644 --- a/android/src/main/java/com/swmansion/enriched/markdown/utils/common/MarkdownViewManagerUtils.kt +++ b/android/src/main/java/com/swmansion/enriched/markdown/utils/common/MarkdownViewManagerUtils.kt @@ -4,9 +4,11 @@ import android.view.View import com.facebook.react.bridge.ReadableArray import com.facebook.react.bridge.ReadableMap import com.facebook.react.uimanager.UIManagerHelper +import com.swmansion.enriched.markdown.events.CitationPressEvent import com.swmansion.enriched.markdown.events.ContextMenuItemPressEvent import com.swmansion.enriched.markdown.events.LinkLongPressEvent import com.swmansion.enriched.markdown.events.LinkPressEvent +import com.swmansion.enriched.markdown.events.MentionPressEvent import com.swmansion.enriched.markdown.events.TaskListItemPressEvent import com.swmansion.enriched.markdown.parser.Md4cFlags @@ -19,6 +21,10 @@ fun markdownEventTypeConstants(): MutableMap { mapOf("registrationName" to TaskListItemPressEvent.EVENT_NAME) map[ContextMenuItemPressEvent.EVENT_NAME] = mapOf("registrationName" to ContextMenuItemPressEvent.EVENT_NAME) + map[MentionPressEvent.EVENT_NAME] = + mapOf("registrationName" to MentionPressEvent.EVENT_NAME) + map[CitationPressEvent.EVENT_NAME] = + mapOf("registrationName" to CitationPressEvent.EVENT_NAME) return map } @@ -42,6 +48,28 @@ fun emitLinkLongPress( eventDispatcher?.dispatchEvent(LinkLongPressEvent(surfaceId, view.id, url)) } +fun emitMentionPress( + view: View, + url: String, + text: String, +) { + val context = view.context as com.facebook.react.bridge.ReactContext + val surfaceId = UIManagerHelper.getSurfaceId(context) + val eventDispatcher = UIManagerHelper.getEventDispatcherForReactTag(context, view.id) + eventDispatcher?.dispatchEvent(MentionPressEvent(surfaceId, view.id, url, text)) +} + +fun emitCitationPress( + view: View, + url: String, + text: String, +) { + val context = view.context as com.facebook.react.bridge.ReactContext + val surfaceId = UIManagerHelper.getSurfaceId(context) + val eventDispatcher = UIManagerHelper.getEventDispatcherForReactTag(context, view.id) + eventDispatcher?.dispatchEvent(CitationPressEvent(surfaceId, view.id, url, text)) +} + fun emitTaskListItemPress( view: View, taskIndex: Int, diff --git a/android/src/main/java/com/swmansion/enriched/markdown/utils/text/conversion/MarkdownExtractor.kt b/android/src/main/java/com/swmansion/enriched/markdown/utils/text/conversion/MarkdownExtractor.kt index 8a79d7f6..9ae5d368 100644 --- a/android/src/main/java/com/swmansion/enriched/markdown/utils/text/conversion/MarkdownExtractor.kt +++ b/android/src/main/java/com/swmansion/enriched/markdown/utils/text/conversion/MarkdownExtractor.kt @@ -5,12 +5,14 @@ import android.text.style.UnderlineSpan import android.widget.TextView import com.swmansion.enriched.markdown.EnrichedMarkdownText import com.swmansion.enriched.markdown.spans.BlockquoteSpan +import com.swmansion.enriched.markdown.spans.CitationSpan import com.swmansion.enriched.markdown.spans.CodeBlockSpan import com.swmansion.enriched.markdown.spans.CodeSpan import com.swmansion.enriched.markdown.spans.EmphasisSpan import com.swmansion.enriched.markdown.spans.HeadingSpan import com.swmansion.enriched.markdown.spans.ImageSpan import com.swmansion.enriched.markdown.spans.LinkSpan +import com.swmansion.enriched.markdown.spans.MentionSpan import com.swmansion.enriched.markdown.spans.OrderedListSpan import com.swmansion.enriched.markdown.spans.StrikethroughSpan import com.swmansion.enriched.markdown.spans.StrongSpan @@ -301,17 +303,21 @@ object MarkdownExtractor { val hasStrikethrough = spannable.getSpans(start, end, StrikethroughSpan::class.java).isNotEmpty() val hasUnderline = spannable.getSpans(start, end, UnderlineSpan::class.java).isNotEmpty() val linkSpans = spannable.getSpans(start, end, LinkSpan::class.java) + val mentionSpans = spannable.getSpans(start, end, MentionSpan::class.java) + val citationSpans = spannable.getSpans(start, end, CitationSpan::class.java) + + val hasAnyLinkShape = linkSpans.isNotEmpty() || mentionSpans.isNotEmpty() || citationSpans.isNotEmpty() var result = text // Innermost first - if (hasCode && linkSpans.isEmpty()) { + if (hasCode && !hasAnyLinkShape) { result = "`$result`" } if (hasStrikethrough) { result = "~~$result~~" } - if (hasUnderline && linkSpans.isEmpty()) { + if (hasUnderline && !hasAnyLinkShape) { result = "$result" } if (hasEmphasis) { @@ -320,9 +326,16 @@ object MarkdownExtractor { if (hasStrong) { result = "**$result**" } - if (linkSpans.isNotEmpty()) { - result = "[$text](${linkSpans[0].url})" - } + // Mentions and citations share the `[text](scheme://url)` shape as regular + // links — just with distinct URL schemes — so a selected range that + // covers one emits the full markdown link, preserving the target URL. + result = + when { + mentionSpans.isNotEmpty() -> "[$text](mention://${mentionSpans[0].url})" + citationSpans.isNotEmpty() -> "[$text](citation://${citationSpans[0].url})" + linkSpans.isNotEmpty() -> "[$text](${linkSpans[0].url})" + else -> result + } return result } diff --git a/android/src/main/java/com/swmansion/enriched/markdown/utils/text/span/SpanFlags.kt b/android/src/main/java/com/swmansion/enriched/markdown/utils/text/span/SpanFlags.kt index b8e9a348..4066be62 100644 --- a/android/src/main/java/com/swmansion/enriched/markdown/utils/text/span/SpanFlags.kt +++ b/android/src/main/java/com/swmansion/enriched/markdown/utils/text/span/SpanFlags.kt @@ -1,5 +1,17 @@ package com.swmansion.enriched.markdown.utils.text.span import android.text.SpannableString +import android.text.Spanned const val SPAN_FLAGS_EXCLUSIVE_EXCLUSIVE = SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE + +/** + * `SPAN_EXCLUSIVE_EXCLUSIVE` with the maximum span priority. + * + * Higher-priority spans are iterated — and therefore drawn — first, so any + * lower-priority span on the same line ends up painted *on top* visually. + * Use this for full-width container backgrounds (e.g. blockquote fill in + * [BlockquoteSpan]) that must sit under inline pill/chip backgrounds. + */ +const val SPAN_FLAGS_CONTAINER_BACKGROUND = + Spanned.SPAN_EXCLUSIVE_EXCLUSIVE or Spanned.SPAN_PRIORITY diff --git a/android/src/main/java/com/swmansion/enriched/markdown/utils/text/view/LinkEvents.kt b/android/src/main/java/com/swmansion/enriched/markdown/utils/text/view/LinkEvents.kt index 1f3e6936..40fcf428 100644 --- a/android/src/main/java/com/swmansion/enriched/markdown/utils/text/view/LinkEvents.kt +++ b/android/src/main/java/com/swmansion/enriched/markdown/utils/text/view/LinkEvents.kt @@ -6,8 +6,10 @@ import android.widget.TextView import com.facebook.react.bridge.ReactContext import com.facebook.react.uimanager.UIManagerHelper import com.facebook.react.uimanager.events.NativeGestureUtil +import com.swmansion.enriched.markdown.events.CitationPressEvent import com.swmansion.enriched.markdown.events.LinkLongPressEvent import com.swmansion.enriched.markdown.events.LinkPressEvent +import com.swmansion.enriched.markdown.events.MentionPressEvent fun View.emitLinkPressEvent(url: String) { val reactContext = context as? ReactContext ?: return @@ -23,6 +25,26 @@ fun View.emitLinkLongPressEvent(url: String) { dispatcher?.dispatchEvent(LinkLongPressEvent(surfaceId, id, url)) } +fun View.emitMentionPressEvent( + url: String, + text: String, +) { + val reactContext = context as? ReactContext ?: return + val surfaceId = UIManagerHelper.getSurfaceId(reactContext) + val dispatcher = UIManagerHelper.getEventDispatcherForReactTag(reactContext, id) + dispatcher?.dispatchEvent(MentionPressEvent(surfaceId, id, url, text)) +} + +fun View.emitCitationPressEvent( + url: String, + text: String, +) { + val reactContext = context as? ReactContext ?: return + val surfaceId = UIManagerHelper.getSurfaceId(reactContext) + val dispatcher = UIManagerHelper.getEventDispatcherForReactTag(reactContext, id) + dispatcher?.dispatchEvent(CitationPressEvent(surfaceId, id, url, text)) +} + /** * Cancels the JS touch for an active link tap, preventing parent * Pressable/TouchableOpacity from firing onPress for the same tap. diff --git a/android/src/main/java/com/swmansion/enriched/markdown/utils/text/view/LinkLongPressMovementMethod.kt b/android/src/main/java/com/swmansion/enriched/markdown/utils/text/view/LinkLongPressMovementMethod.kt index 401e11e5..7d692ad4 100644 --- a/android/src/main/java/com/swmansion/enriched/markdown/utils/text/view/LinkLongPressMovementMethod.kt +++ b/android/src/main/java/com/swmansion/enriched/markdown/utils/text/view/LinkLongPressMovementMethod.kt @@ -8,12 +8,24 @@ import android.text.method.LinkMovementMethod import android.view.MotionEvent import android.view.ViewConfiguration import android.widget.TextView +import com.swmansion.enriched.markdown.spans.CitationSpan import com.swmansion.enriched.markdown.spans.LinkSpan +import com.swmansion.enriched.markdown.spans.MentionSpan import com.swmansion.enriched.markdown.spans.SpoilerSpan import com.swmansion.enriched.markdown.spoiler.SpoilerCapable import kotlin.math.abs class LinkLongPressMovementMethod : LinkMovementMethod() { + /** + * Optional callback invoked when a [MentionSpan] is tapped. The mention pill + * is a [android.text.style.ReplacementSpan], not a [android.text.style.ClickableSpan], + * so the standard LinkMovementMethod dispatch doesn't reach it. + */ + var onMentionTap: ((url: String, text: String) -> Unit)? = null + + /** Optional callback invoked when a [CitationSpan] is tapped. */ + var onCitationTap: ((url: String, text: String) -> Unit)? = null + private val handler = Handler(Looper.getMainLooper()) private var longPressRunnable: Runnable? = null @@ -23,6 +35,10 @@ class LinkLongPressMovementMethod : LinkMovementMethod() { var isLinkTouchActive: Boolean = false private set + private var activeMentionSpan: MentionSpan? = null + private var pendingMentionTapOffset: Int = -1 + private var pendingCitationTapOffset: Int = -1 + override fun onTouchEvent( widget: TextView, buffer: Spannable, @@ -36,6 +52,19 @@ class LinkLongPressMovementMethod : LinkMovementMethod() { val span = findLinkSpan(widget, buffer, event) isLinkTouchActive = span != null span?.let { scheduleLongPress(widget, it) } + + findMentionSpan(widget, buffer, event)?.let { mention -> + activeMentionSpan = mention + mention.isPressed = true + widget.invalidate() + pendingMentionTapOffset = charOffsetAt(widget, event) ?: -1 + } + + if (activeMentionSpan == null) { + findCitationSpan(widget, buffer, event)?.let { _ -> + pendingCitationTapOffset = charOffsetAt(widget, event) ?: -1 + } + } } MotionEvent.ACTION_MOVE -> { @@ -45,6 +74,8 @@ class LinkLongPressMovementMethod : LinkMovementMethod() { ) { cancelLongPress() isLinkTouchActive = false + clearMentionPressedState(widget) + pendingCitationTapOffset = -1 } } @@ -56,13 +87,44 @@ class LinkLongPressMovementMethod : LinkMovementMethod() { } if (handleSpoilerTap(widget, buffer, event)) { Selection.removeSelection(buffer) + clearMentionPressedState(widget) + pendingCitationTapOffset = -1 return true } + + val mention = activeMentionSpan + if (mention != null) { + // Only emit if finger is still over the same mention span. + val stillOverMention = findMentionSpan(widget, buffer, event) === mention + clearMentionPressedState(widget) + pendingMentionTapOffset = -1 + if (stillOverMention) { + onMentionTap?.invoke(mention.url, mention.displayText) + return true + } + } + + if (pendingCitationTapOffset >= 0) { + val currentOffset = charOffsetAt(widget, event) ?: -1 + val citation = + if (currentOffset >= 0) { + buffer.getSpans(currentOffset, currentOffset, CitationSpan::class.java).firstOrNull() + } else { + null + } + pendingCitationTapOffset = -1 + if (citation != null) { + onCitationTap?.invoke(citation.url, citation.displayText) + return true + } + } } MotionEvent.ACTION_CANCEL -> { cancelLongPress() isLinkTouchActive = false + clearMentionPressedState(widget) + pendingCitationTapOffset = -1 if (widget.hasSelection()) { Selection.removeSelection(buffer) } @@ -127,6 +189,32 @@ class LinkLongPressMovementMethod : LinkMovementMethod() { return buffer.getSpans(offset, offset, LinkSpan::class.java).firstOrNull() } + private fun findMentionSpan( + widget: TextView, + buffer: Spannable, + event: MotionEvent, + ): MentionSpan? { + val offset = charOffsetAt(widget, event) ?: return null + return buffer.getSpans(offset, offset, MentionSpan::class.java).firstOrNull() + } + + private fun findCitationSpan( + widget: TextView, + buffer: Spannable, + event: MotionEvent, + ): CitationSpan? { + val offset = charOffsetAt(widget, event) ?: return null + return buffer.getSpans(offset, offset, CitationSpan::class.java).firstOrNull() + } + + private fun clearMentionPressedState(widget: TextView) { + activeMentionSpan?.let { + it.isPressed = false + widget.invalidate() + } + activeMentionSpan = null + } + private fun handleSpoilerTap( widget: TextView, buffer: Spannable, diff --git a/android/src/main/java/com/swmansion/enriched/markdown/utils/text/view/SelectionActionMode.kt b/android/src/main/java/com/swmansion/enriched/markdown/utils/text/view/SelectionActionMode.kt index e358b1e2..e5e30a66 100644 --- a/android/src/main/java/com/swmansion/enriched/markdown/utils/text/view/SelectionActionMode.kt +++ b/android/src/main/java/com/swmansion/enriched/markdown/utils/text/view/SelectionActionMode.kt @@ -11,6 +11,7 @@ import android.view.ViewParent import android.widget.TextView import com.swmansion.enriched.markdown.EnrichedMarkdown import com.swmansion.enriched.markdown.EnrichedMarkdownText +import com.swmansion.enriched.markdown.spans.CitationSpan import com.swmansion.enriched.markdown.spans.ImageSpan import com.swmansion.enriched.markdown.styles.StyleConfig import com.swmansion.enriched.markdown.utils.common.layout.isLayoutRTL @@ -123,7 +124,10 @@ private fun TextView.copyWithHTML() { val spannable = text as? Spannable ?: return val selectedText = spannable.subSequence(start, end) - val plainText = selectedText.toString() + // Citation text (e.g. superscript markers) is reference metadata, not prose; + // strip it from the plain-text flavor so pasting into a plain text target + // yields clean copy. Rich flavors (HTML below) still keep the marker. + val plainText = buildPlainTextWithoutCitations(selectedText) val styleConfig = (this as? EnrichedMarkdownText)?.markdownStyle @@ -148,6 +152,38 @@ private fun TextView.copyWithHTML() { } } +/** + * Rebuilds a plain-text string from a selected CharSequence with any ranges + * tagged by a [CitationSpan] elided. The selection is indexed from 0, so span + * positions need to be translated against the passed-in CharSequence. + */ +private fun buildPlainTextWithoutCitations(selection: CharSequence): String { + if (selection !is Spannable) return selection.toString() + + val spans = selection.getSpans(0, selection.length, CitationSpan::class.java) + if (spans.isEmpty()) return selection.toString() + + // Collect non-overlapping, non-zero-length ranges sorted by start index. + val ranges = + spans + .map { selection.getSpanStart(it) to selection.getSpanEnd(it) } + .filter { it.second > it.first } + .sortedBy { it.first } + + val result = StringBuilder(selection.length) + var cursor = 0 + for ((spanStart, spanEnd) in ranges) { + if (spanStart > cursor) { + result.append(selection.subSequence(cursor, spanStart)) + } + cursor = maxOf(cursor, spanEnd) + } + if (cursor < selection.length) { + result.append(selection.subSequence(cursor, selection.length)) + } + return result.toString() +} + private fun TextView.copyMarkdownToClipboard() { val markdown = MarkdownExtractor.getMarkdownForSelection(this) ?: return val clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager diff --git a/android/src/main/java/com/swmansion/enriched/markdown/utils/text/view/TextSelectionColors.kt b/android/src/main/java/com/swmansion/enriched/markdown/utils/text/view/TextSelectionColors.kt new file mode 100644 index 00000000..1a6d7242 --- /dev/null +++ b/android/src/main/java/com/swmansion/enriched/markdown/utils/text/view/TextSelectionColors.kt @@ -0,0 +1,48 @@ +package com.swmansion.enriched.markdown.utils.text.view + +import android.graphics.drawable.Drawable +import android.os.Build +import android.util.Log +import android.widget.TextView +import androidx.annotation.ColorInt +import androidx.core.graphics.drawable.DrawableCompat + +private const val TAG = "TextSelectionColors" + +private typealias HandleGetter = (TextView) -> Drawable? +private typealias HandleSetter = (TextView, Drawable) -> Unit + +/** + * Applies selection highlight and (where supported) handle tinting to a [TextView]. + * + * Handle drawables are only tinted on API 29+ where the framework exposes getters; + * on older versions the handle theme defaults remain unchanged. + */ +fun TextView.applySelectionColors( + selectionColor: Int?, + selectionHandleColor: Int?, +) { + selectionColor?.let { highlightColor = it } + selectionHandleColor?.let { applySelectionHandleTint(it) } +} + +private fun TextView.applySelectionHandleTint( + @ColorInt color: Int, +) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) return + + val handles: List> = + listOf( + TextView::getTextSelectHandleLeft to { tv, d -> tv.setTextSelectHandleLeft(d) }, + TextView::getTextSelectHandle to { tv, d -> tv.setTextSelectHandle(d) }, + TextView::getTextSelectHandleRight to { tv, d -> tv.setTextSelectHandleRight(d) }, + ) + + handles.forEach { (getter, setter) -> + try { + getter(this)?.mutate()?.also { DrawableCompat.setTint(it, color) }?.let { setter(this, it) } + } catch (e: LinkageError) { + Log.w(TAG, "Selection handle tint skipped: ${e.message}") + } + } +} diff --git a/android/src/main/java/com/swmansion/enriched/markdown/views/TableContainerView.kt b/android/src/main/java/com/swmansion/enriched/markdown/views/TableContainerView.kt index a9c6f6d2..6606f5fe 100644 --- a/android/src/main/java/com/swmansion/enriched/markdown/views/TableContainerView.kt +++ b/android/src/main/java/com/swmansion/enriched/markdown/views/TableContainerView.kt @@ -49,6 +49,8 @@ class TableContainerView( var maxFontSizeMultiplier = 0f var onLinkPress: ((String) -> Unit)? = null var onLinkLongPress: ((String) -> Unit)? = null + var onMentionPress: ((url: String, text: String) -> Unit)? = null + var onCitationPress: ((url: String, text: String) -> Unit)? = null private val scrollView = HorizontalScrollView(context).apply { @@ -206,6 +208,10 @@ class TableContainerView( showContextMenu(view) true } + (movementMethod as? LinkLongPressMovementMethod)?.apply { + onMentionTap = { url, mentionText -> this@TableContainerView.onMentionPress?.invoke(url, mentionText) } + onCitationTap = { url, citationText -> this@TableContainerView.onCitationPress?.invoke(url, citationText) } + } } val horizontalPadding = tableStyle.cellPaddingHorizontal val verticalPadding = tableStyle.cellPaddingVertical diff --git a/apps/example/Gemfile b/apps/example/Gemfile index 6a4c5f17..2163ea08 100644 --- a/apps/example/Gemfile +++ b/apps/example/Gemfile @@ -14,3 +14,5 @@ gem 'bigdecimal' gem 'logger' gem 'benchmark' gem 'mutex_m' +# kconv was removed from stdlib; CFPropertyList (CocoaPods) still expects it via nkf. +gem 'nkf' diff --git a/apps/example/Gemfile.lock b/apps/example/Gemfile.lock index 4c317a6d..075ae447 100644 --- a/apps/example/Gemfile.lock +++ b/apps/example/Gemfile.lock @@ -2,7 +2,7 @@ GEM remote: https://rubygems.org/ specs: CFPropertyList (3.0.8) - activesupport (7.2.3) + activesupport (7.2.3.1) base64 benchmark (>= 0.3) bigdecimal @@ -11,10 +11,10 @@ GEM drb i18n (>= 1.6, < 2) logger (>= 1.4.2) - minitest (>= 5.1) + minitest (>= 5.1, < 6) securerandom (>= 0.3) tzinfo (~> 2.0, >= 2.0.5) - addressable (2.8.9) + addressable (2.9.0) public_suffix (>= 2.0.2, < 8.0) algoliasearch (1.27.5) httpclient (~> 2.8, >= 2.8.3) @@ -22,7 +22,7 @@ GEM atomos (0.1.3) base64 (0.3.0) benchmark (0.5.0) - bigdecimal (4.0.1) + bigdecimal (4.1.1) claide (1.1.0) cocoapods (1.15.2) addressable (~> 2.8) @@ -66,9 +66,10 @@ GEM connection_pool (3.0.2) drb (2.2.3) escape (0.0.4) - ethon (0.15.0) + ethon (0.18.0) ffi (>= 1.15.0) - ffi (1.17.3) + logger + ffi (1.17.4) fourflusher (2.3.1) fuzzy_match (2.0.4) gh_inspector (1.1.3) @@ -76,23 +77,21 @@ GEM mutex_m i18n (1.14.8) concurrent-ruby (~> 1.0) - json (2.18.1) + json (2.19.3) logger (1.7.0) - minitest (6.0.2) - drb (~> 2.0) - prism (~> 1.5) + minitest (5.27.0) molinillo (0.8.0) mutex_m (0.3.0) nanaimo (0.3.0) nap (1.1.0) netrc (0.11.0) - prism (1.9.0) + nkf (0.2.0) public_suffix (4.0.7) rexml (3.4.4) ruby-macho (2.5.1) securerandom (0.4.1) - typhoeus (1.5.0) - ethon (>= 0.9.0, < 0.16.0) + typhoeus (1.6.0) + ethon (>= 0.18.0) tzinfo (2.0.6) concurrent-ruby (~> 1.0) xcodeproj (1.25.1) @@ -114,6 +113,7 @@ DEPENDENCIES concurrent-ruby (< 1.3.4) logger mutex_m + nkf xcodeproj (< 1.26.0) RUBY VERSION diff --git a/apps/example/ios/Podfile.lock b/apps/example/ios/Podfile.lock index b2737490..0d13aa35 100644 --- a/apps/example/ios/Podfile.lock +++ b/apps/example/ios/Podfile.lock @@ -2117,7 +2117,11 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: FBLazyVector: e97c19a5a442429d1988f182a1940fb08df514da +<<<<<<< HEAD hermes-engine: b0f9c82a51be8e938eb979ada628323e1e093f1d +======= + hermes-engine: f6578d972f9b73b756304d62c2537e7f69329eca +>>>>>>> feat/mention-and-citation-links iosMath: f7a6cbadf9d836d2149c2a84c435b1effc244cba RCTDeprecation: af44b104091a34482596cd9bd7e8d90c4e9b4bd7 RCTRequired: bb77b070f75f53398ce43c0aaaa58337cebe2bf6 @@ -2127,7 +2131,11 @@ SPEC CHECKSUMS: React: 1ba7d364ade7d883a1ec055bfc3606f35fdee17b React-callinvoker: bc2a26f8d84fb01f003fc6de6c9337b64715f95b React-Core: 7840d3a80b43a95c5e80ef75146bd70925ebab0f +<<<<<<< HEAD React-Core-prebuilt: 3dc04e91547fc0f260f4b84c12da0f672b813862 +======= + React-Core-prebuilt: e5482a51694507e64658e1c0be8753a92fc4e849 +>>>>>>> feat/mention-and-citation-links React-CoreModules: 2eb010400b63b89e53a324ffb3c112e4c7c3ce42 React-cxxreact: a558e92199d26f145afa9e62c4233cf8e7950efe React-debug: 755200a6e7f5e6e0a40ff8d215493d43cce285fc @@ -2189,8 +2197,8 @@ SPEC CHECKSUMS: ReactAppDependencyProvider: e96e93b493d8d86eeaee3e590ba0be53f6abe46f ReactCodegen: 797de5178718324c6eba3327b07f9a423fbd5787 ReactCommon: 07572bf9e687c8a52fbe4a3641e9e3a1a477c78e - ReactNativeDependencies: 44f7326a697de7f6c8629036b1a4689f0e64c684 - ReactNativeEnrichedMarkdown: 1daba1851810704ba2f5c6e5fff638a94661e317 + ReactNativeDependencies: f2497ee045a976e64dec20d371611288e835df1f + ReactNativeEnrichedMarkdown: 63665119b6d5c634c76f5f4caf46dc4ebd23863e Yoga: c0b3f2c7e8d3e327e450223a2414ca3fa296b9a2 PODFILE CHECKSUM: 9c5417fc84515945aa2357a49779fde55434ae62 diff --git a/apps/example/src/App.tsx b/apps/example/src/App.tsx index e4c44a7a..1972c707 100644 --- a/apps/example/src/App.tsx +++ b/apps/example/src/App.tsx @@ -11,6 +11,8 @@ import { import { EnrichedMarkdownText, type LinkPressEvent, + type CitationPressEvent, + type MentionPressEvent, } from 'react-native-enriched-markdown'; import { SafeAreaView } from 'react-native-safe-area-context'; import { sampleMarkdown } from './sampleMarkdown'; @@ -63,6 +65,38 @@ export default function App() { ]); }; + const handleCitationPress = (event: CitationPressEvent) => { + const { url } = event; + Alert.alert('Citation Pressed!', `You tapped on: ${url}`, [ + { + text: 'Open in Browser', + onPress: () => { + Linking.openURL(url); + }, + }, + { + text: 'Cancel', + style: 'cancel', + }, + ]); + }; + + const handleMentionPress = (event: MentionPressEvent) => { + const { url } = event; + Alert.alert('Mention Pressed!', `You tapped on: ${url}`, [ + { + text: 'Open in Browser', + onPress: () => { + Linking.openURL(url); + }, + }, + { + text: 'Cancel', + style: 'cancel', + }, + ]); + }; + return ( @@ -91,8 +125,12 @@ export default function App() { flavor="github" markdown={sampleMarkdown} onLinkPress={handleLinkPress} + onCitationPress={handleCitationPress} + onMentionPress={handleMentionPress} markdownStyle={markdownStyle} contextMenuItems={contextMenuItems} + selectionColor={Platform.OS === 'ios' ? '#5A52FA' : '#DCDDFE'} + selectionHandleColor="#5A52FA" /> )} diff --git a/apps/example/src/markdownStyles.ts b/apps/example/src/markdownStyles.ts index 8bc6f79d..f37df644 100644 --- a/apps/example/src/markdownStyles.ts +++ b/apps/example/src/markdownStyles.ts @@ -143,4 +143,28 @@ export const customMarkdownStyle: MarkdownStyle = { checkedTextColor: '#9ca3af', checkedStrikethrough: true, }, + mention: { + backgroundColor: '#EBEBFF', + borderColor: '#ddd6fe', + borderWidth: 1, + borderRadius: 99, + paddingHorizontal: 4, + paddingVertical: 0, + fontFamily: 'Montserrat-Regular', + fontSize: 14, + color: '#2561fB', + }, + citation: { + backgroundColor: '#EBEBFF', + color: '#9B9BFD', + fontSizeMultiplier: 0.6, + baselineOffsetPx: 8, + fontWeight: '', + underline: false, + paddingHorizontal: 4, + paddingVertical: 4, + borderColor: '#ddd6fe', + borderWidth: 1, + borderRadius: 99, + }, }; diff --git a/apps/example/src/sampleMarkdown.ts b/apps/example/src/sampleMarkdown.ts index bb7263dc..6b8ae799 100644 --- a/apps/example/src/sampleMarkdown.ts +++ b/apps/example/src/sampleMarkdown.ts @@ -1,5 +1,5 @@ export const sampleMarkdown = ` -# The Hidden World of Forest Ecosystems +# The Hidden World of Forest Ecosystems!! Forests cover approximately **31% of the Earth's land surface**, providing habitat for countless species and playing a vital role in our planet's health. These magnificent ecosystems have existed for over *300 million years*, evolving alongside the creatures that call them home. @@ -11,15 +11,15 @@ Forests cover approximately **31% of the Earth's land surface**, providing habit Forests are often called the *lungs of the Earth*. They absorb **carbon dioxide** and release oxygen through photosynthesis — a process essential for all life on our planet. A single mature tree can absorb up to \`48 pounds\` of CO₂ per year. -> In every walk with nature, one receives far more than he seeks. +> In every walk with nature, one receives far more than he seeks. \`test code\` > > — John Muir ### Key Benefits -- **Climate regulation** through carbon sequestration -- *Biodiversity* hotspots supporting millions of species -- Natural water filtration and ***flood prevention*** +- **Climate regulation** through carbon sequestration [@Casper](mention://d81546aa-5f91-408a-b6dd-628e324750bf?type=user) [@Arby](mention://d81546aa-5f91-408a-b6dd-628e324750bf?type=user) +- *Biodiversity* hotspots supporting millions of species [+resume software engineer](mention://Uploads/twilio-script.py?type=file) +- Natural water filtration and ***flood prevention*** [1](citation://https://www.google.com) [2](citation://https://www.google.com?q=123) [3](citation://https://www.google.com?q=123&abc=123) [4](citation://https://www.google.com?q=123) [5](citation://https://www.google.com?q=123) [6](citation://https://www.google.com?q=123) [7](citation://https://www.google.com?q=123) [8](citation://https://www.google.com?q=123) [9](citation://https://www.google.com?q=123) [10](citation://https://www.google.com?q=123) - Source of medicine, food, and raw materials - Soil erosion prevention and **nutrient cycling** - Recreation and *mental health* benefits @@ -28,7 +28,7 @@ Forests are often called the *lungs of the Earth*. They absorb **carbon dioxide* Forests contribute over **$1.3 trillion** to the global economy annually. They provide: -- Timber and *wood products* +- Timber and *wood products* [4](citation://https://www.google.com) [5](citation://https://www.google.com) [6](citation://https://www.google.com) [7](citation://https://www.google.com) [8](citation://https://www.google.com) [9](citation://https://www.google.com) [7](citation://https://www.google.com) - Non-timber forest products like **nuts and berries** - Ecotourism opportunities - ***Carbon credits*** for climate mitigation @@ -104,10 +104,10 @@ The largest terrestrial biome, spanning across **Northern Russia, Canada, and Sc | Forest Type | Coverage | Annual Rainfall | Biodiversity | Carbon Storage | |------------|----------|-----------------|--------------|----------------| -| Tropical Rainforest | ~7% of land | 80-400 inches | Highest (50%+ species) | High | -| Temperate Forest | ~16% of land | 30-60 inches | Moderate | Moderate | +| Tropical Rainforest [4](citation://https://www.google.com) [5](citation://https://www.google.com) | ~7% of land | 80-400 inches | Highest (50%+ species) | High | +| Temperate Forest [@Casper](mention://d81546aa-5f91-408a-b6dd-628e324750bf?type=user) | ~16% of land | 30-60 inches | Moderate | Moderate | | Boreal Forest (Taiga) | ~11% of land | 15-40 inches | Lower | Highest | -| Mediterranean Forest | ~2% of land | 20-40 inches | Moderate | Moderate | +| Mediterranean Forest | ~2% of land | 20-40 inches | Moderate | Moderate [@John Muir](mention://d81546aa-5f91-408a-b6dd-628e324750bf?type=user)| --- @@ -136,7 +136,7 @@ class TreeNetwork { this.trees = []; this.fungalConnections = new Map(); } - + connectTrees(tree1, tree2) { // Trees share nutrients through mycorrhizal networks this.fungalConnections.set(\`\${tree1.id}-\${tree2.id}\`, { @@ -309,6 +309,14 @@ Conservation efforts are making a difference: | ***The Nature Conservancy*** | Land protection | Protected 125M+ acres | | One Tree Planted | Reforestation | Planted 100M+ trees | + +| Organization | Focus Area | +|--------------|------------| +| **WFF** | Global conservation | +| *RA* | Sustainable agriculture | +| ***TNC*** | Land protection | +| ***OTP*** | Reforestation | + --- ## The Future of Forests @@ -330,11 +338,11 @@ def detect_deforestation(region): """Monitor forest cover changes using satellite imagery""" current_cover = satellite_imagery.get_forest_cover(region) previous_cover = satellite_imagery.get_historical_cover(region, years_ago=1) - + deforestation_rate = (previous_cover - current_cover) / previous_cover if deforestation_rate > 0.05: # 5% threshold alert_conservation_team(region, deforestation_rate) - + return deforestation_rate \`\`\` diff --git a/apps/macos-example/src/sampleMarkdown.ts b/apps/macos-example/src/sampleMarkdown.ts index 1fd851b9..f4deab3d 100644 --- a/apps/macos-example/src/sampleMarkdown.ts +++ b/apps/macos-example/src/sampleMarkdown.ts @@ -122,7 +122,7 @@ class TreeNetwork { this.trees = []; this.fungalConnections = new Map(); } - + connectTrees(tree1, tree2) { // Trees share nutrients through mycorrhizal networks this.fungalConnections.set(\`\${tree1.id}-\${tree2.id}\`, { @@ -316,11 +316,11 @@ def detect_deforestation(region): """Monitor forest cover changes using satellite imagery""" current_cover = satellite_imagery.get_forest_cover(region) previous_cover = satellite_imagery.get_historical_cover(region, years_ago=1) - + deforestation_rate = (previous_cover - current_cover) / previous_cover if deforestation_rate > 0.05: # 5% threshold alert_conservation_team(region, deforestation_rate) - + return deforestation_rate \`\`\` diff --git a/apps/web-example/src/App.tsx b/apps/web-example/src/App.tsx index 7547f280..fb496873 100644 --- a/apps/web-example/src/App.tsx +++ b/apps/web-example/src/App.tsx @@ -5,6 +5,8 @@ import type { LinkPressEvent, LinkLongPressEvent, TaskListItemPressEvent, + CitationPressEvent, + MentionPressEvent, } from 'react-native-enriched-markdown'; import { sampleMarkdown } from './sampleMarkdown'; @@ -96,7 +98,7 @@ console.log(greet("العالم")); `.trim(); interface EventLog { - kind: 'link' | 'linkLong' | 'task'; + kind: 'link' | 'linkLong' | 'task' | 'citation' | 'mention'; label: string; detail: string; } @@ -105,6 +107,8 @@ const KIND_COLOR: Record = { link: '#2563EB', linkLong: '#7C3AED', task: '#059669', + citation: '#9B9BFD', + mention: '#2563EB', }; export default function App() { @@ -130,6 +134,18 @@ export default function App() { [] ); + const handleCitationPress = (event: CitationPressEvent) => { + const { url } = event; + setLastEvent({ kind: 'citation', label: 'onCitationPress', detail: url }); + Linking.openURL(url); + }; + + const handleMentionPress = (event: MentionPressEvent) => { + const { url } = event; + setLastEvent({ kind: 'mention', label: 'onMentionPress', detail: url }); + Linking.openURL(url); + }; + return ( @@ -153,6 +169,35 @@ export default function App() { onLinkPress={onLinkPress} onLinkLongPress={onLinkLongPress} onTaskListItemPress={onTaskListItemPress} + onCitationPress={handleCitationPress} + onMentionPress={handleMentionPress} + markdownStyle={{ + mention: { + backgroundColor: '#EBEBFF', + borderColor: '#ddd6fe', + borderWidth: 1, + borderRadius: 99, + paddingHorizontal: 4, + paddingVertical: 0, + fontSize: 14, + color: '#2563fb', + }, + citation: { + backgroundColor: '#EBEBFF', + color: '#9B9BFD', + fontSizeMultiplier: 0.5, + baselineOffsetPx: 7, + fontWeight: '', + underline: false, + paddingHorizontal: 2, + paddingVertical: 2, + borderColor: '#ddd6fe', + borderWidth: 1, + borderRadius: 99, + }, + }} + selectionColor="#DCDDFE" + selectionHandleColor="#5A52FA" /> diff --git a/ios/EnrichedMarkdown.mm b/ios/EnrichedMarkdown.mm index 9227b789..2ac6c906 100644 --- a/ios/EnrichedMarkdown.mm +++ b/ios/EnrichedMarkdown.mm @@ -7,6 +7,7 @@ #import "EditMenuUtils.h" #import "ENRMFeatureFlags.h" +#import "ENRMUIKit.h" #if ENRICHED_MARKDOWN_MATH #import "ENRMMathContainerView.h" @@ -33,10 +34,10 @@ #import #import -#import -#import -#import -#import +#import "internals/EnrichedMarkdownComponentDescriptor.h" +#import +#import +#import #import "RCTFabricComponentsPlugins.h" #import @@ -90,6 +91,7 @@ + (instancetype)segmentWithLatex:(NSString *)latex #endif @interface EnrichedMarkdown () +- (void)applySelectionColor:(const EnrichedMarkdownProps &)props toTextView:(ENRMPlatformTextView *)textView; @end @implementation EnrichedMarkdown { @@ -493,6 +495,9 @@ - (EnrichedMarkdownInternalText *)createTextViewForRenderedSegment:(ENRMRenderRe view.textView.selectable = _selectable; [view applyAttributedText:segment.attributedText context:segment.context]; + const auto &selectionProps = *std::static_pointer_cast(self->_props); + [self applySelectionColor:selectionProps toTextView:view.textView]; + ENRMTapRecognizer *tapRecognizer = [[ENRMTapRecognizer alloc] initWithTarget:self action:@selector(textTapped:)]; [view.textView addGestureRecognizer:tapRecognizer]; @@ -559,6 +564,34 @@ - (TableContainerView *)createTableViewForSegment:(EMTableSegment *)tableSegment } }; + tableView.onMentionPress = ^(NSString *url, NSString *text) { + EnrichedMarkdown *strongSelf = weakSelf; + if (!strongSelf) + return; + + auto eventEmitter = std::static_pointer_cast(strongSelf->_eventEmitter); + if (eventEmitter) { + eventEmitter->onMentionPress({ + .url = std::string([(url ?: @"") UTF8String] ?: ""), + .text = std::string([(text ?: @"") UTF8String] ?: ""), + }); + } + }; + + tableView.onCitationPress = ^(NSString *url, NSString *text) { + EnrichedMarkdown *strongSelf = weakSelf; + if (!strongSelf) + return; + + auto eventEmitter = std::static_pointer_cast(strongSelf->_eventEmitter); + if (eventEmitter) { + eventEmitter->onCitationPress({ + .url = std::string([(url ?: @"") UTF8String] ?: ""), + .text = std::string([(text ?: @"") UTF8String] ?: ""), + }); + } + }; + [tableView applyTableNode:tableSegment.tableNode]; return tableView; @@ -657,6 +690,17 @@ - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const & } } + if (newViewProps.selectionColor != oldViewProps.selectionColor) { +#if !TARGET_OS_OSX + for (RCTUIView *segment in _segmentViews) { + if ([segment isKindOfClass:[EnrichedMarkdownInternalText class]]) { + ENRMPlatformTextView *tv = ((EnrichedMarkdownInternalText *)segment).textView; + [self applySelectionColor:newViewProps toTextView:tv]; + } + } +#endif + } + if (markdownChanged || stylePropChanged || md4cFlagsChanged || allowTrailingMarginChanged) { NSString *markdownString = [[NSString alloc] initWithUTF8String:newViewProps.markdown.c_str()]; [self renderMarkdownContent:markdownString]; @@ -760,11 +804,28 @@ - (void)textTapped:(ENRMTapRecognizer *)recognizer } } - NSString *url = linkURLAtTapLocation(textView, recognizer); - if (url) { + NSString *linkURL = nil; + NSString *mentionURL = nil; + NSString *mentionText = nil; + NSString *citationURL = nil; + NSString *citationText = nil; + if (inlineElementAtTapLocation(textView, recognizer, &linkURL, &mentionURL, &mentionText, &citationURL, + &citationText)) { auto eventEmitter = std::static_pointer_cast(_eventEmitter); if (eventEmitter) { - eventEmitter->onLinkPress({.url = std::string([url UTF8String])}); + if (mentionURL) { + eventEmitter->onMentionPress({ + .url = std::string([mentionURL UTF8String] ?: ""), + .text = std::string([(mentionText ?: @"") UTF8String] ?: ""), + }); + } else if (citationURL) { + eventEmitter->onCitationPress({ + .url = std::string([citationURL UTF8String] ?: ""), + .text = std::string([(citationText ?: @"") UTF8String] ?: ""), + }); + } else if (linkURL) { + eventEmitter->onLinkPress({.url = std::string([linkURL UTF8String])}); + } } return; } @@ -880,4 +941,15 @@ - (NSInteger)indexOfAccessibilityElement:(id)element } #endif +- (void)applySelectionColor:(const EnrichedMarkdownProps &)props toTextView:(ENRMPlatformTextView *)textView +{ +#if !TARGET_OS_OSX + if (isColorMeaningful(props.selectionColor)) { + ENRMSetSelectionColor(textView, RCTUIColorFromSharedColor(props.selectionColor)); + } else { + ENRMSetSelectionColor(textView, nil); + } +#endif +} + @end diff --git a/ios/EnrichedMarkdownText.mm b/ios/EnrichedMarkdownText.mm index 239e435a..f410c455 100644 --- a/ios/EnrichedMarkdownText.mm +++ b/ios/EnrichedMarkdownText.mm @@ -9,6 +9,7 @@ #import "ENRMTailFadeInAnimator.h" #import "ENRMTextRenderer.h" #import "ENRMTextViewSetup.h" +#import "ENRMUIKit.h" #import "EditMenuUtils.h" #import "FontScaleObserver.h" #import "FontUtils.h" @@ -22,10 +23,10 @@ #import "StylePropsUtils.h" #import "TaskListTapUtils.h" -#import -#import -#import -#import +#import "internals/EnrichedMarkdownTextComponentDescriptor.h" +#import +#import +#import #import "RCTFabricComponentsPlugins.h" #import @@ -411,6 +412,16 @@ - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const & _textView.selectable = newViewProps.selectable; } + if (newViewProps.selectionColor != oldViewProps.selectionColor) { +#if !TARGET_OS_OSX + if (isColorMeaningful(newViewProps.selectionColor)) { + ENRMSetSelectionColor(_textView, RCTUIColorFromSharedColor(newViewProps.selectionColor)); + } else { + ENRMSetSelectionColor(_textView, nil); + } +#endif + } + if (newViewProps.allowFontScaling != oldViewProps.allowFontScaling) { _fontScaleObserver.allowFontScaling = newViewProps.allowFontScaling; @@ -537,11 +548,28 @@ - (void)textTapped:(ENRMTapRecognizer *)recognizer return; } - NSString *url = linkURLAtTapLocation(textView, recognizer); - if (url) { + NSString *linkURL = nil; + NSString *mentionURL = nil; + NSString *mentionText = nil; + NSString *citationURL = nil; + NSString *citationText = nil; + if (inlineElementAtTapLocation(textView, recognizer, &linkURL, &mentionURL, &mentionText, &citationURL, + &citationText)) { auto eventEmitter = std::static_pointer_cast(_eventEmitter); if (eventEmitter) { - eventEmitter->onLinkPress({.url = std::string([url UTF8String])}); + if (mentionURL) { + eventEmitter->onMentionPress({ + .url = std::string([mentionURL UTF8String] ?: ""), + .text = std::string([(mentionText ?: @"") UTF8String] ?: ""), + }); + } else if (citationURL) { + eventEmitter->onCitationPress({ + .url = std::string([citationURL UTF8String] ?: ""), + .text = std::string([(citationText ?: @"") UTF8String] ?: ""), + }); + } else if (linkURL) { + eventEmitter->onLinkPress({.url = std::string([linkURL UTF8String])}); + } } return; } diff --git a/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/ComponentDescriptors.cpp b/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/ComponentDescriptors.cpp new file mode 100644 index 00000000..4d59d519 --- /dev/null +++ b/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/ComponentDescriptors.cpp @@ -0,0 +1,22 @@ + +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateComponentDescriptorCpp.js + */ + +#include "ComponentDescriptors.h" +#include +#include + +namespace facebook::react { + +void EnrichedMarkdownTextSpec_registerComponentDescriptorsFromCodegen( + std::shared_ptr registry) { + +} + +} // namespace facebook::react diff --git a/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/ComponentDescriptors.h b/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/ComponentDescriptors.h new file mode 100644 index 00000000..06510880 --- /dev/null +++ b/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/ComponentDescriptors.h @@ -0,0 +1,24 @@ + +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateComponentDescriptorH.js + */ + +#pragma once + +#include "ShadowNodes.h" +#include +#include + +namespace facebook::react { + + + +void EnrichedMarkdownTextSpec_registerComponentDescriptorsFromCodegen( + std::shared_ptr registry); + +} // namespace facebook::react diff --git a/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/EventEmitters.cpp b/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/EventEmitters.cpp new file mode 100644 index 00000000..d3570ab7 --- /dev/null +++ b/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/EventEmitters.cpp @@ -0,0 +1,314 @@ + +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateEventEmitterCpp.js + */ + +#include "EventEmitters.h" + + +namespace facebook::react { + +void EnrichedMarkdownEventEmitter::onLinkPress(OnLinkPress event) const { + dispatchEvent("linkPress", [event=std::move(event)](jsi::Runtime &runtime) { + auto payload = jsi::Object(runtime); + payload.setProperty(runtime, "url", event.url); + return payload; + }); +} + + +void EnrichedMarkdownEventEmitter::onLinkLongPress(OnLinkLongPress event) const { + dispatchEvent("linkLongPress", [event=std::move(event)](jsi::Runtime &runtime) { + auto payload = jsi::Object(runtime); + payload.setProperty(runtime, "url", event.url); + return payload; + }); +} + + +void EnrichedMarkdownEventEmitter::onTaskListItemPress(OnTaskListItemPress event) const { + dispatchEvent("taskListItemPress", [event=std::move(event)](jsi::Runtime &runtime) { + auto payload = jsi::Object(runtime); + payload.setProperty(runtime, "index", event.index); +payload.setProperty(runtime, "checked", event.checked); +payload.setProperty(runtime, "text", event.text); + return payload; + }); +} + + +void EnrichedMarkdownEventEmitter::onMentionPress(OnMentionPress event) const { + dispatchEvent("mentionPress", [event=std::move(event)](jsi::Runtime &runtime) { + auto payload = jsi::Object(runtime); + payload.setProperty(runtime, "url", event.url); +payload.setProperty(runtime, "text", event.text); + return payload; + }); +} + + +void EnrichedMarkdownEventEmitter::onCitationPress(OnCitationPress event) const { + dispatchEvent("citationPress", [event=std::move(event)](jsi::Runtime &runtime) { + auto payload = jsi::Object(runtime); + payload.setProperty(runtime, "url", event.url); +payload.setProperty(runtime, "text", event.text); + return payload; + }); +} + + +void EnrichedMarkdownEventEmitter::onContextMenuItemPress(OnContextMenuItemPress event) const { + dispatchEvent("contextMenuItemPress", [event=std::move(event)](jsi::Runtime &runtime) { + auto payload = jsi::Object(runtime); + payload.setProperty(runtime, "itemText", event.itemText); +payload.setProperty(runtime, "selectedText", event.selectedText); +payload.setProperty(runtime, "selectionStart", event.selectionStart); +payload.setProperty(runtime, "selectionEnd", event.selectionEnd); + return payload; + }); +} + + +void EnrichedMarkdownTextInputEventEmitter::onChangeText(OnChangeText event) const { + dispatchEvent("changeText", [event=std::move(event)](jsi::Runtime &runtime) { + auto payload = jsi::Object(runtime); + payload.setProperty(runtime, "value", event.value); + return payload; + }); +} + + +void EnrichedMarkdownTextInputEventEmitter::onChangeMarkdown(OnChangeMarkdown event) const { + dispatchEvent("changeMarkdown", [event=std::move(event)](jsi::Runtime &runtime) { + auto payload = jsi::Object(runtime); + payload.setProperty(runtime, "value", event.value); + return payload; + }); +} + + +void EnrichedMarkdownTextInputEventEmitter::onChangeSelection(OnChangeSelection event) const { + dispatchEvent("changeSelection", [event=std::move(event)](jsi::Runtime &runtime) { + auto payload = jsi::Object(runtime); + payload.setProperty(runtime, "start", event.start); +payload.setProperty(runtime, "end", event.end); + return payload; + }); +} + + +void EnrichedMarkdownTextInputEventEmitter::onChangeState(OnChangeState event) const { + dispatchEvent("changeState", [event=std::move(event)](jsi::Runtime &runtime) { + auto payload = jsi::Object(runtime); + { + auto bold = jsi::Object(runtime); + bold.setProperty(runtime, "isActive", event.bold.isActive); + payload.setProperty(runtime, "bold", bold); +} +{ + auto italic = jsi::Object(runtime); + italic.setProperty(runtime, "isActive", event.italic.isActive); + payload.setProperty(runtime, "italic", italic); +} +{ + auto underline = jsi::Object(runtime); + underline.setProperty(runtime, "isActive", event.underline.isActive); + payload.setProperty(runtime, "underline", underline); +} +{ + auto strikethrough = jsi::Object(runtime); + strikethrough.setProperty(runtime, "isActive", event.strikethrough.isActive); + payload.setProperty(runtime, "strikethrough", strikethrough); +} +{ + auto spoiler = jsi::Object(runtime); + spoiler.setProperty(runtime, "isActive", event.spoiler.isActive); + payload.setProperty(runtime, "spoiler", spoiler); +} +{ + auto link = jsi::Object(runtime); + link.setProperty(runtime, "isActive", event.link.isActive); + payload.setProperty(runtime, "link", link); +} + return payload; + }); +} + + +void EnrichedMarkdownTextInputEventEmitter::onInputFocus(OnInputFocus event) const { + dispatchEvent("inputFocus", [event=std::move(event)](jsi::Runtime &runtime) { + auto payload = jsi::Object(runtime); + payload.setProperty(runtime, "target", event.target); + return payload; + }); +} + + +void EnrichedMarkdownTextInputEventEmitter::onInputBlur(OnInputBlur event) const { + dispatchEvent("inputBlur", [event=std::move(event)](jsi::Runtime &runtime) { + auto payload = jsi::Object(runtime); + payload.setProperty(runtime, "target", event.target); + return payload; + }); +} + + +void EnrichedMarkdownTextInputEventEmitter::onRequestMarkdownResult(OnRequestMarkdownResult event) const { + dispatchEvent("requestMarkdownResult", [event=std::move(event)](jsi::Runtime &runtime) { + auto payload = jsi::Object(runtime); + payload.setProperty(runtime, "requestId", event.requestId); +payload.setProperty(runtime, "markdown", event.markdown); + return payload; + }); +} + + +void EnrichedMarkdownTextInputEventEmitter::onRequestCaretRectResult(OnRequestCaretRectResult event) const { + dispatchEvent("requestCaretRectResult", [event=std::move(event)](jsi::Runtime &runtime) { + auto payload = jsi::Object(runtime); + payload.setProperty(runtime, "requestId", event.requestId); +payload.setProperty(runtime, "x", event.x); +payload.setProperty(runtime, "y", event.y); +payload.setProperty(runtime, "width", event.width); +payload.setProperty(runtime, "height", event.height); + return payload; + }); +} + + +void EnrichedMarkdownTextInputEventEmitter::onCaretRectChange(OnCaretRectChange event) const { + dispatchEvent("caretRectChange", [event=std::move(event)](jsi::Runtime &runtime) { + auto payload = jsi::Object(runtime); + payload.setProperty(runtime, "x", event.x); +payload.setProperty(runtime, "y", event.y); +payload.setProperty(runtime, "width", event.width); +payload.setProperty(runtime, "height", event.height); + return payload; + }); +} + + +void EnrichedMarkdownTextInputEventEmitter::onContextMenuItemPress(OnContextMenuItemPress event) const { + dispatchEvent("contextMenuItemPress", [event=std::move(event)](jsi::Runtime &runtime) { + auto payload = jsi::Object(runtime); + payload.setProperty(runtime, "itemText", event.itemText); +payload.setProperty(runtime, "selectedText", event.selectedText); +payload.setProperty(runtime, "selectionStart", event.selectionStart); +payload.setProperty(runtime, "selectionEnd", event.selectionEnd); +{ + auto styleState = jsi::Object(runtime); + { + auto bold = jsi::Object(runtime); + bold.setProperty(runtime, "isActive", event.styleState.bold.isActive); + styleState.setProperty(runtime, "bold", bold); + } + { + auto italic = jsi::Object(runtime); + italic.setProperty(runtime, "isActive", event.styleState.italic.isActive); + styleState.setProperty(runtime, "italic", italic); + } + { + auto underline = jsi::Object(runtime); + underline.setProperty(runtime, "isActive", event.styleState.underline.isActive); + styleState.setProperty(runtime, "underline", underline); + } + { + auto strikethrough = jsi::Object(runtime); + strikethrough.setProperty(runtime, "isActive", event.styleState.strikethrough.isActive); + styleState.setProperty(runtime, "strikethrough", strikethrough); + } + { + auto spoiler = jsi::Object(runtime); + spoiler.setProperty(runtime, "isActive", event.styleState.spoiler.isActive); + styleState.setProperty(runtime, "spoiler", spoiler); + } + { + auto link = jsi::Object(runtime); + link.setProperty(runtime, "isActive", event.styleState.link.isActive); + styleState.setProperty(runtime, "link", link); + } + payload.setProperty(runtime, "styleState", styleState); +} + return payload; + }); +} + + +void EnrichedMarkdownTextInputEventEmitter::onLinkDetected(OnLinkDetected event) const { + dispatchEvent("linkDetected", [event=std::move(event)](jsi::Runtime &runtime) { + auto payload = jsi::Object(runtime); + payload.setProperty(runtime, "text", event.text); +payload.setProperty(runtime, "url", event.url); +payload.setProperty(runtime, "start", event.start); +payload.setProperty(runtime, "end", event.end); + return payload; + }); +} + + +void EnrichedMarkdownTextEventEmitter::onLinkPress(OnLinkPress event) const { + dispatchEvent("linkPress", [event=std::move(event)](jsi::Runtime &runtime) { + auto payload = jsi::Object(runtime); + payload.setProperty(runtime, "url", event.url); + return payload; + }); +} + + +void EnrichedMarkdownTextEventEmitter::onLinkLongPress(OnLinkLongPress event) const { + dispatchEvent("linkLongPress", [event=std::move(event)](jsi::Runtime &runtime) { + auto payload = jsi::Object(runtime); + payload.setProperty(runtime, "url", event.url); + return payload; + }); +} + + +void EnrichedMarkdownTextEventEmitter::onTaskListItemPress(OnTaskListItemPress event) const { + dispatchEvent("taskListItemPress", [event=std::move(event)](jsi::Runtime &runtime) { + auto payload = jsi::Object(runtime); + payload.setProperty(runtime, "index", event.index); +payload.setProperty(runtime, "checked", event.checked); +payload.setProperty(runtime, "text", event.text); + return payload; + }); +} + + +void EnrichedMarkdownTextEventEmitter::onMentionPress(OnMentionPress event) const { + dispatchEvent("mentionPress", [event=std::move(event)](jsi::Runtime &runtime) { + auto payload = jsi::Object(runtime); + payload.setProperty(runtime, "url", event.url); +payload.setProperty(runtime, "text", event.text); + return payload; + }); +} + + +void EnrichedMarkdownTextEventEmitter::onCitationPress(OnCitationPress event) const { + dispatchEvent("citationPress", [event=std::move(event)](jsi::Runtime &runtime) { + auto payload = jsi::Object(runtime); + payload.setProperty(runtime, "url", event.url); +payload.setProperty(runtime, "text", event.text); + return payload; + }); +} + + +void EnrichedMarkdownTextEventEmitter::onContextMenuItemPress(OnContextMenuItemPress event) const { + dispatchEvent("contextMenuItemPress", [event=std::move(event)](jsi::Runtime &runtime) { + auto payload = jsi::Object(runtime); + payload.setProperty(runtime, "itemText", event.itemText); +payload.setProperty(runtime, "selectedText", event.selectedText); +payload.setProperty(runtime, "selectionStart", event.selectionStart); +payload.setProperty(runtime, "selectionEnd", event.selectionEnd); + return payload; + }); +} + +} // namespace facebook::react diff --git a/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/EventEmitters.h b/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/EventEmitters.h new file mode 100644 index 00000000..a0421da6 --- /dev/null +++ b/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/EventEmitters.h @@ -0,0 +1,255 @@ + +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateEventEmitterH.js + */ +#pragma once + +#include + + +namespace facebook::react { +class EnrichedMarkdownEventEmitter : public ViewEventEmitter { + public: + using ViewEventEmitter::ViewEventEmitter; + + struct OnLinkPress { + std::string url; + }; + + struct OnLinkLongPress { + std::string url; + }; + + struct OnTaskListItemPress { + int index; + bool checked; + std::string text; + }; + + struct OnMentionPress { + std::string url; + std::string text; + }; + + struct OnCitationPress { + std::string url; + std::string text; + }; + + struct OnContextMenuItemPress { + std::string itemText; + std::string selectedText; + int selectionStart; + int selectionEnd; + }; + void onLinkPress(OnLinkPress value) const; + + void onLinkLongPress(OnLinkLongPress value) const; + + void onTaskListItemPress(OnTaskListItemPress value) const; + + void onMentionPress(OnMentionPress value) const; + + void onCitationPress(OnCitationPress value) const; + + void onContextMenuItemPress(OnContextMenuItemPress value) const; +}; +class EnrichedMarkdownTextInputEventEmitter : public ViewEventEmitter { + public: + using ViewEventEmitter::ViewEventEmitter; + + struct OnChangeText { + std::string value; + }; + + struct OnChangeMarkdown { + std::string value; + }; + + struct OnChangeSelection { + int start; + int end; + }; + + struct OnChangeStateBold { + bool isActive; + }; + + struct OnChangeStateItalic { + bool isActive; + }; + + struct OnChangeStateUnderline { + bool isActive; + }; + + struct OnChangeStateStrikethrough { + bool isActive; + }; + + struct OnChangeStateSpoiler { + bool isActive; + }; + + struct OnChangeStateLink { + bool isActive; + }; + + struct OnChangeState { + OnChangeStateBold bold; + OnChangeStateItalic italic; + OnChangeStateUnderline underline; + OnChangeStateStrikethrough strikethrough; + OnChangeStateSpoiler spoiler; + OnChangeStateLink link; + }; + + struct OnInputFocus { + int target; + }; + + struct OnInputBlur { + int target; + }; + + struct OnRequestMarkdownResult { + int requestId; + std::string markdown; + }; + + struct OnRequestCaretRectResult { + int requestId; + double x; + double y; + double width; + double height; + }; + + struct OnCaretRectChange { + double x; + double y; + double width; + double height; + }; + + struct OnContextMenuItemPressStyleStateBold { + bool isActive; + }; + + struct OnContextMenuItemPressStyleStateItalic { + bool isActive; + }; + + struct OnContextMenuItemPressStyleStateUnderline { + bool isActive; + }; + + struct OnContextMenuItemPressStyleStateStrikethrough { + bool isActive; + }; + + struct OnContextMenuItemPressStyleStateSpoiler { + bool isActive; + }; + + struct OnContextMenuItemPressStyleStateLink { + bool isActive; + }; + + struct OnContextMenuItemPressStyleState { + OnContextMenuItemPressStyleStateBold bold; + OnContextMenuItemPressStyleStateItalic italic; + OnContextMenuItemPressStyleStateUnderline underline; + OnContextMenuItemPressStyleStateStrikethrough strikethrough; + OnContextMenuItemPressStyleStateSpoiler spoiler; + OnContextMenuItemPressStyleStateLink link; + }; + + struct OnContextMenuItemPress { + std::string itemText; + std::string selectedText; + int selectionStart; + int selectionEnd; + OnContextMenuItemPressStyleState styleState; + }; + + struct OnLinkDetected { + std::string text; + std::string url; + int start; + int end; + }; + void onChangeText(OnChangeText value) const; + + void onChangeMarkdown(OnChangeMarkdown value) const; + + void onChangeSelection(OnChangeSelection value) const; + + void onChangeState(OnChangeState value) const; + + void onInputFocus(OnInputFocus value) const; + + void onInputBlur(OnInputBlur value) const; + + void onRequestMarkdownResult(OnRequestMarkdownResult value) const; + + void onRequestCaretRectResult(OnRequestCaretRectResult value) const; + + void onCaretRectChange(OnCaretRectChange value) const; + + void onContextMenuItemPress(OnContextMenuItemPress value) const; + + void onLinkDetected(OnLinkDetected value) const; +}; +class EnrichedMarkdownTextEventEmitter : public ViewEventEmitter { + public: + using ViewEventEmitter::ViewEventEmitter; + + struct OnLinkPress { + std::string url; + }; + + struct OnLinkLongPress { + std::string url; + }; + + struct OnTaskListItemPress { + int index; + bool checked; + std::string text; + }; + + struct OnMentionPress { + std::string url; + std::string text; + }; + + struct OnCitationPress { + std::string url; + std::string text; + }; + + struct OnContextMenuItemPress { + std::string itemText; + std::string selectedText; + int selectionStart; + int selectionEnd; + }; + void onLinkPress(OnLinkPress value) const; + + void onLinkLongPress(OnLinkLongPress value) const; + + void onTaskListItemPress(OnTaskListItemPress value) const; + + void onMentionPress(OnMentionPress value) const; + + void onCitationPress(OnCitationPress value) const; + + void onContextMenuItemPress(OnContextMenuItemPress value) const; +}; +} // namespace facebook::react diff --git a/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/Props.cpp b/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/Props.cpp new file mode 100644 index 00000000..0b4e8f2f --- /dev/null +++ b/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/Props.cpp @@ -0,0 +1,315 @@ + +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GeneratePropsCpp.js + */ + +#include "Props.h" +#include +#include + +namespace facebook::react { + +EnrichedMarkdownProps::EnrichedMarkdownProps( + const PropsParserContext &context, + const EnrichedMarkdownProps &sourceProps, + const RawProps &rawProps): ViewProps(context, sourceProps, rawProps), + + markdown(convertRawProp(context, rawProps, "markdown", sourceProps.markdown, {})), + markdownStyle(convertRawProp(context, rawProps, "markdownStyle", sourceProps.markdownStyle, {})), + enableLinkPreview(convertRawProp(context, rawProps, "enableLinkPreview", sourceProps.enableLinkPreview, {true})), + selectable(convertRawProp(context, rawProps, "selectable", sourceProps.selectable, {false})), + selectionColor(convertRawProp(context, rawProps, "selectionColor", sourceProps.selectionColor, {})), + selectionHandleColor(convertRawProp(context, rawProps, "selectionHandleColor", sourceProps.selectionHandleColor, {})), + md4cFlags(convertRawProp(context, rawProps, "md4cFlags", sourceProps.md4cFlags, {})), + allowFontScaling(convertRawProp(context, rawProps, "allowFontScaling", sourceProps.allowFontScaling, {true})), + maxFontSizeMultiplier(convertRawProp(context, rawProps, "maxFontSizeMultiplier", sourceProps.maxFontSizeMultiplier, {0.0})), + allowTrailingMargin(convertRawProp(context, rawProps, "allowTrailingMargin", sourceProps.allowTrailingMargin, {false})), + streamingAnimation(convertRawProp(context, rawProps, "streamingAnimation", sourceProps.streamingAnimation, {false})), + spoilerOverlay(convertRawProp(context, rawProps, "spoilerOverlay", sourceProps.spoilerOverlay, {std::string{"particles"}})), + contextMenuItems(convertRawProp(context, rawProps, "contextMenuItems", sourceProps.contextMenuItems, {})) {} + +#ifdef RN_SERIALIZABLE_STATE +ComponentName EnrichedMarkdownProps::getDiffPropsImplementationTarget() const { + return "EnrichedMarkdown"; +} + +folly::dynamic EnrichedMarkdownProps::getDiffProps( + const Props* prevProps) const { + static const auto defaultProps = EnrichedMarkdownProps(); + const EnrichedMarkdownProps* oldProps = prevProps == nullptr + ? &defaultProps + : static_cast(prevProps); + if (this == oldProps) { + return folly::dynamic::object(); + } + folly::dynamic result = HostPlatformViewProps::getDiffProps(prevProps); + + if (markdown != oldProps->markdown) { + result["markdown"] = markdown; + } + + if (markdownStyle != oldProps->markdownStyle) { + result["markdownStyle"] = toDynamic(markdownStyle); + } + + if (enableLinkPreview != oldProps->enableLinkPreview) { + result["enableLinkPreview"] = enableLinkPreview; + } + + if (selectable != oldProps->selectable) { + result["selectable"] = selectable; + } + + if (selectionColor != oldProps->selectionColor) { + result["selectionColor"] = *selectionColor; + } + + if (selectionHandleColor != oldProps->selectionHandleColor) { + result["selectionHandleColor"] = *selectionHandleColor; + } + + if (md4cFlags != oldProps->md4cFlags) { + result["md4cFlags"] = toDynamic(md4cFlags); + } + + if (allowFontScaling != oldProps->allowFontScaling) { + result["allowFontScaling"] = allowFontScaling; + } + + if ((maxFontSizeMultiplier != oldProps->maxFontSizeMultiplier) && !(std::isnan(maxFontSizeMultiplier) && std::isnan(oldProps->maxFontSizeMultiplier))) { + result["maxFontSizeMultiplier"] = maxFontSizeMultiplier; + } + + if (allowTrailingMargin != oldProps->allowTrailingMargin) { + result["allowTrailingMargin"] = allowTrailingMargin; + } + + if (streamingAnimation != oldProps->streamingAnimation) { + result["streamingAnimation"] = streamingAnimation; + } + + if (spoilerOverlay != oldProps->spoilerOverlay) { + result["spoilerOverlay"] = spoilerOverlay; + } + + if (contextMenuItems != oldProps->contextMenuItems) { + result["contextMenuItems"] = toDynamic(contextMenuItems); + } + return result; +} +#endif +EnrichedMarkdownTextInputProps::EnrichedMarkdownTextInputProps( + const PropsParserContext &context, + const EnrichedMarkdownTextInputProps &sourceProps, + const RawProps &rawProps): ViewProps(context, sourceProps, rawProps), + + defaultValue(convertRawProp(context, rawProps, "defaultValue", sourceProps.defaultValue, {})), + placeholder(convertRawProp(context, rawProps, "placeholder", sourceProps.placeholder, {})), + placeholderTextColor(convertRawProp(context, rawProps, "placeholderTextColor", sourceProps.placeholderTextColor, {})), + editable(convertRawProp(context, rawProps, "editable", sourceProps.editable, {false})), + autoFocus(convertRawProp(context, rawProps, "autoFocus", sourceProps.autoFocus, {false})), + scrollEnabled(convertRawProp(context, rawProps, "scrollEnabled", sourceProps.scrollEnabled, {false})), + autoCapitalize(convertRawProp(context, rawProps, "autoCapitalize", sourceProps.autoCapitalize, {})), + multiline(convertRawProp(context, rawProps, "multiline", sourceProps.multiline, {false})), + cursorColor(convertRawProp(context, rawProps, "cursorColor", sourceProps.cursorColor, {})), + selectionColor(convertRawProp(context, rawProps, "selectionColor", sourceProps.selectionColor, {})), + markdownStyle(convertRawProp(context, rawProps, "markdownStyle", sourceProps.markdownStyle, {})), + color(convertRawProp(context, rawProps, "color", sourceProps.color, {})), + fontSize(convertRawProp(context, rawProps, "fontSize", sourceProps.fontSize, {0.0})), + lineHeight(convertRawProp(context, rawProps, "lineHeight", sourceProps.lineHeight, {0.0})), + fontFamily(convertRawProp(context, rawProps, "fontFamily", sourceProps.fontFamily, {})), + fontWeight(convertRawProp(context, rawProps, "fontWeight", sourceProps.fontWeight, {})), + isOnChangeMarkdownSet(convertRawProp(context, rawProps, "isOnChangeMarkdownSet", sourceProps.isOnChangeMarkdownSet, {false})), + contextMenuItems(convertRawProp(context, rawProps, "contextMenuItems", sourceProps.contextMenuItems, {})), + linkRegex(convertRawProp(context, rawProps, "linkRegex", sourceProps.linkRegex, {})) {} + +#ifdef RN_SERIALIZABLE_STATE +ComponentName EnrichedMarkdownTextInputProps::getDiffPropsImplementationTarget() const { + return "EnrichedMarkdownTextInput"; +} + +folly::dynamic EnrichedMarkdownTextInputProps::getDiffProps( + const Props* prevProps) const { + static const auto defaultProps = EnrichedMarkdownTextInputProps(); + const EnrichedMarkdownTextInputProps* oldProps = prevProps == nullptr + ? &defaultProps + : static_cast(prevProps); + if (this == oldProps) { + return folly::dynamic::object(); + } + folly::dynamic result = HostPlatformViewProps::getDiffProps(prevProps); + + if (defaultValue != oldProps->defaultValue) { + result["defaultValue"] = defaultValue; + } + + if (placeholder != oldProps->placeholder) { + result["placeholder"] = placeholder; + } + + if (placeholderTextColor != oldProps->placeholderTextColor) { + result["placeholderTextColor"] = *placeholderTextColor; + } + + if (editable != oldProps->editable) { + result["editable"] = editable; + } + + if (autoFocus != oldProps->autoFocus) { + result["autoFocus"] = autoFocus; + } + + if (scrollEnabled != oldProps->scrollEnabled) { + result["scrollEnabled"] = scrollEnabled; + } + + if (autoCapitalize != oldProps->autoCapitalize) { + result["autoCapitalize"] = autoCapitalize; + } + + if (multiline != oldProps->multiline) { + result["multiline"] = multiline; + } + + if (cursorColor != oldProps->cursorColor) { + result["cursorColor"] = *cursorColor; + } + + if (selectionColor != oldProps->selectionColor) { + result["selectionColor"] = *selectionColor; + } + + if (markdownStyle != oldProps->markdownStyle) { + result["markdownStyle"] = toDynamic(markdownStyle); + } + + if (color != oldProps->color) { + result["color"] = *color; + } + + if ((fontSize != oldProps->fontSize) && !(std::isnan(fontSize) && std::isnan(oldProps->fontSize))) { + result["fontSize"] = fontSize; + } + + if ((lineHeight != oldProps->lineHeight) && !(std::isnan(lineHeight) && std::isnan(oldProps->lineHeight))) { + result["lineHeight"] = lineHeight; + } + + if (fontFamily != oldProps->fontFamily) { + result["fontFamily"] = fontFamily; + } + + if (fontWeight != oldProps->fontWeight) { + result["fontWeight"] = fontWeight; + } + + if (isOnChangeMarkdownSet != oldProps->isOnChangeMarkdownSet) { + result["isOnChangeMarkdownSet"] = isOnChangeMarkdownSet; + } + + if (contextMenuItems != oldProps->contextMenuItems) { + result["contextMenuItems"] = toDynamic(contextMenuItems); + } + + if (linkRegex != oldProps->linkRegex) { + result["linkRegex"] = toDynamic(linkRegex); + } + return result; +} +#endif +EnrichedMarkdownTextProps::EnrichedMarkdownTextProps( + const PropsParserContext &context, + const EnrichedMarkdownTextProps &sourceProps, + const RawProps &rawProps): ViewProps(context, sourceProps, rawProps), + + markdown(convertRawProp(context, rawProps, "markdown", sourceProps.markdown, {})), + markdownStyle(convertRawProp(context, rawProps, "markdownStyle", sourceProps.markdownStyle, {})), + enableLinkPreview(convertRawProp(context, rawProps, "enableLinkPreview", sourceProps.enableLinkPreview, {true})), + selectable(convertRawProp(context, rawProps, "selectable", sourceProps.selectable, {false})), + selectionColor(convertRawProp(context, rawProps, "selectionColor", sourceProps.selectionColor, {})), + selectionHandleColor(convertRawProp(context, rawProps, "selectionHandleColor", sourceProps.selectionHandleColor, {})), + md4cFlags(convertRawProp(context, rawProps, "md4cFlags", sourceProps.md4cFlags, {})), + allowFontScaling(convertRawProp(context, rawProps, "allowFontScaling", sourceProps.allowFontScaling, {true})), + maxFontSizeMultiplier(convertRawProp(context, rawProps, "maxFontSizeMultiplier", sourceProps.maxFontSizeMultiplier, {0.0})), + allowTrailingMargin(convertRawProp(context, rawProps, "allowTrailingMargin", sourceProps.allowTrailingMargin, {false})), + streamingAnimation(convertRawProp(context, rawProps, "streamingAnimation", sourceProps.streamingAnimation, {false})), + spoilerOverlay(convertRawProp(context, rawProps, "spoilerOverlay", sourceProps.spoilerOverlay, {std::string{"particles"}})), + contextMenuItems(convertRawProp(context, rawProps, "contextMenuItems", sourceProps.contextMenuItems, {})) {} + +#ifdef RN_SERIALIZABLE_STATE +ComponentName EnrichedMarkdownTextProps::getDiffPropsImplementationTarget() const { + return "EnrichedMarkdownText"; +} + +folly::dynamic EnrichedMarkdownTextProps::getDiffProps( + const Props* prevProps) const { + static const auto defaultProps = EnrichedMarkdownTextProps(); + const EnrichedMarkdownTextProps* oldProps = prevProps == nullptr + ? &defaultProps + : static_cast(prevProps); + if (this == oldProps) { + return folly::dynamic::object(); + } + folly::dynamic result = HostPlatformViewProps::getDiffProps(prevProps); + + if (markdown != oldProps->markdown) { + result["markdown"] = markdown; + } + + if (markdownStyle != oldProps->markdownStyle) { + result["markdownStyle"] = toDynamic(markdownStyle); + } + + if (enableLinkPreview != oldProps->enableLinkPreview) { + result["enableLinkPreview"] = enableLinkPreview; + } + + if (selectable != oldProps->selectable) { + result["selectable"] = selectable; + } + + if (selectionColor != oldProps->selectionColor) { + result["selectionColor"] = *selectionColor; + } + + if (selectionHandleColor != oldProps->selectionHandleColor) { + result["selectionHandleColor"] = *selectionHandleColor; + } + + if (md4cFlags != oldProps->md4cFlags) { + result["md4cFlags"] = toDynamic(md4cFlags); + } + + if (allowFontScaling != oldProps->allowFontScaling) { + result["allowFontScaling"] = allowFontScaling; + } + + if ((maxFontSizeMultiplier != oldProps->maxFontSizeMultiplier) && !(std::isnan(maxFontSizeMultiplier) && std::isnan(oldProps->maxFontSizeMultiplier))) { + result["maxFontSizeMultiplier"] = maxFontSizeMultiplier; + } + + if (allowTrailingMargin != oldProps->allowTrailingMargin) { + result["allowTrailingMargin"] = allowTrailingMargin; + } + + if (streamingAnimation != oldProps->streamingAnimation) { + result["streamingAnimation"] = streamingAnimation; + } + + if (spoilerOverlay != oldProps->spoilerOverlay) { + result["spoilerOverlay"] = spoilerOverlay; + } + + if (contextMenuItems != oldProps->contextMenuItems) { + result["contextMenuItems"] = toDynamic(contextMenuItems); + } + return result; +} +#endif + +} // namespace facebook::react diff --git a/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/Props.h b/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/Props.h new file mode 100644 index 00000000..659b7066 --- /dev/null +++ b/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/Props.h @@ -0,0 +1,4674 @@ + +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GeneratePropsH.js + */ +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace facebook::react { + +struct EnrichedMarkdownMarkdownStyleParagraphStruct { + Float fontSize{0.0}; + std::string fontFamily{}; + std::string fontWeight{}; + SharedColor color{}; + Float marginTop{0.0}; + Float marginBottom{0.0}; + Float lineHeight{0.0}; + std::string textAlign{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownMarkdownStyleParagraphStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["fontSize"] = fontSize; + result["fontFamily"] = fontFamily; + result["fontWeight"] = fontWeight; + result["color"] = ::facebook::react::toDynamic(color); + result["marginTop"] = marginTop; + result["marginBottom"] = marginBottom; + result["lineHeight"] = lineHeight; + result["textAlign"] = textAlign; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownMarkdownStyleParagraphStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_fontSize = map.find("fontSize"); + if (tmp_fontSize != map.end()) { + fromRawValue(context, tmp_fontSize->second, result.fontSize); + } + auto tmp_fontFamily = map.find("fontFamily"); + if (tmp_fontFamily != map.end()) { + fromRawValue(context, tmp_fontFamily->second, result.fontFamily); + } + auto tmp_fontWeight = map.find("fontWeight"); + if (tmp_fontWeight != map.end()) { + fromRawValue(context, tmp_fontWeight->second, result.fontWeight); + } + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } + auto tmp_marginTop = map.find("marginTop"); + if (tmp_marginTop != map.end()) { + fromRawValue(context, tmp_marginTop->second, result.marginTop); + } + auto tmp_marginBottom = map.find("marginBottom"); + if (tmp_marginBottom != map.end()) { + fromRawValue(context, tmp_marginBottom->second, result.marginBottom); + } + auto tmp_lineHeight = map.find("lineHeight"); + if (tmp_lineHeight != map.end()) { + fromRawValue(context, tmp_lineHeight->second, result.lineHeight); + } + auto tmp_textAlign = map.find("textAlign"); + if (tmp_textAlign != map.end()) { + fromRawValue(context, tmp_textAlign->second, result.textAlign); + } +} + +static inline std::string toString(const EnrichedMarkdownMarkdownStyleParagraphStruct &value) { + return "[Object EnrichedMarkdownMarkdownStyleParagraphStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownMarkdownStyleParagraphStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownMarkdownStyleH1Struct { + Float fontSize{0.0}; + std::string fontFamily{}; + std::string fontWeight{}; + SharedColor color{}; + Float marginTop{0.0}; + Float marginBottom{0.0}; + Float lineHeight{0.0}; + std::string textAlign{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownMarkdownStyleH1Struct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["fontSize"] = fontSize; + result["fontFamily"] = fontFamily; + result["fontWeight"] = fontWeight; + result["color"] = ::facebook::react::toDynamic(color); + result["marginTop"] = marginTop; + result["marginBottom"] = marginBottom; + result["lineHeight"] = lineHeight; + result["textAlign"] = textAlign; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownMarkdownStyleH1Struct &result) { + auto map = (std::unordered_map)value; + + auto tmp_fontSize = map.find("fontSize"); + if (tmp_fontSize != map.end()) { + fromRawValue(context, tmp_fontSize->second, result.fontSize); + } + auto tmp_fontFamily = map.find("fontFamily"); + if (tmp_fontFamily != map.end()) { + fromRawValue(context, tmp_fontFamily->second, result.fontFamily); + } + auto tmp_fontWeight = map.find("fontWeight"); + if (tmp_fontWeight != map.end()) { + fromRawValue(context, tmp_fontWeight->second, result.fontWeight); + } + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } + auto tmp_marginTop = map.find("marginTop"); + if (tmp_marginTop != map.end()) { + fromRawValue(context, tmp_marginTop->second, result.marginTop); + } + auto tmp_marginBottom = map.find("marginBottom"); + if (tmp_marginBottom != map.end()) { + fromRawValue(context, tmp_marginBottom->second, result.marginBottom); + } + auto tmp_lineHeight = map.find("lineHeight"); + if (tmp_lineHeight != map.end()) { + fromRawValue(context, tmp_lineHeight->second, result.lineHeight); + } + auto tmp_textAlign = map.find("textAlign"); + if (tmp_textAlign != map.end()) { + fromRawValue(context, tmp_textAlign->second, result.textAlign); + } +} + +static inline std::string toString(const EnrichedMarkdownMarkdownStyleH1Struct &value) { + return "[Object EnrichedMarkdownMarkdownStyleH1Struct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownMarkdownStyleH1Struct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownMarkdownStyleH2Struct { + Float fontSize{0.0}; + std::string fontFamily{}; + std::string fontWeight{}; + SharedColor color{}; + Float marginTop{0.0}; + Float marginBottom{0.0}; + Float lineHeight{0.0}; + std::string textAlign{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownMarkdownStyleH2Struct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["fontSize"] = fontSize; + result["fontFamily"] = fontFamily; + result["fontWeight"] = fontWeight; + result["color"] = ::facebook::react::toDynamic(color); + result["marginTop"] = marginTop; + result["marginBottom"] = marginBottom; + result["lineHeight"] = lineHeight; + result["textAlign"] = textAlign; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownMarkdownStyleH2Struct &result) { + auto map = (std::unordered_map)value; + + auto tmp_fontSize = map.find("fontSize"); + if (tmp_fontSize != map.end()) { + fromRawValue(context, tmp_fontSize->second, result.fontSize); + } + auto tmp_fontFamily = map.find("fontFamily"); + if (tmp_fontFamily != map.end()) { + fromRawValue(context, tmp_fontFamily->second, result.fontFamily); + } + auto tmp_fontWeight = map.find("fontWeight"); + if (tmp_fontWeight != map.end()) { + fromRawValue(context, tmp_fontWeight->second, result.fontWeight); + } + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } + auto tmp_marginTop = map.find("marginTop"); + if (tmp_marginTop != map.end()) { + fromRawValue(context, tmp_marginTop->second, result.marginTop); + } + auto tmp_marginBottom = map.find("marginBottom"); + if (tmp_marginBottom != map.end()) { + fromRawValue(context, tmp_marginBottom->second, result.marginBottom); + } + auto tmp_lineHeight = map.find("lineHeight"); + if (tmp_lineHeight != map.end()) { + fromRawValue(context, tmp_lineHeight->second, result.lineHeight); + } + auto tmp_textAlign = map.find("textAlign"); + if (tmp_textAlign != map.end()) { + fromRawValue(context, tmp_textAlign->second, result.textAlign); + } +} + +static inline std::string toString(const EnrichedMarkdownMarkdownStyleH2Struct &value) { + return "[Object EnrichedMarkdownMarkdownStyleH2Struct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownMarkdownStyleH2Struct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownMarkdownStyleH3Struct { + Float fontSize{0.0}; + std::string fontFamily{}; + std::string fontWeight{}; + SharedColor color{}; + Float marginTop{0.0}; + Float marginBottom{0.0}; + Float lineHeight{0.0}; + std::string textAlign{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownMarkdownStyleH3Struct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["fontSize"] = fontSize; + result["fontFamily"] = fontFamily; + result["fontWeight"] = fontWeight; + result["color"] = ::facebook::react::toDynamic(color); + result["marginTop"] = marginTop; + result["marginBottom"] = marginBottom; + result["lineHeight"] = lineHeight; + result["textAlign"] = textAlign; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownMarkdownStyleH3Struct &result) { + auto map = (std::unordered_map)value; + + auto tmp_fontSize = map.find("fontSize"); + if (tmp_fontSize != map.end()) { + fromRawValue(context, tmp_fontSize->second, result.fontSize); + } + auto tmp_fontFamily = map.find("fontFamily"); + if (tmp_fontFamily != map.end()) { + fromRawValue(context, tmp_fontFamily->second, result.fontFamily); + } + auto tmp_fontWeight = map.find("fontWeight"); + if (tmp_fontWeight != map.end()) { + fromRawValue(context, tmp_fontWeight->second, result.fontWeight); + } + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } + auto tmp_marginTop = map.find("marginTop"); + if (tmp_marginTop != map.end()) { + fromRawValue(context, tmp_marginTop->second, result.marginTop); + } + auto tmp_marginBottom = map.find("marginBottom"); + if (tmp_marginBottom != map.end()) { + fromRawValue(context, tmp_marginBottom->second, result.marginBottom); + } + auto tmp_lineHeight = map.find("lineHeight"); + if (tmp_lineHeight != map.end()) { + fromRawValue(context, tmp_lineHeight->second, result.lineHeight); + } + auto tmp_textAlign = map.find("textAlign"); + if (tmp_textAlign != map.end()) { + fromRawValue(context, tmp_textAlign->second, result.textAlign); + } +} + +static inline std::string toString(const EnrichedMarkdownMarkdownStyleH3Struct &value) { + return "[Object EnrichedMarkdownMarkdownStyleH3Struct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownMarkdownStyleH3Struct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownMarkdownStyleH4Struct { + Float fontSize{0.0}; + std::string fontFamily{}; + std::string fontWeight{}; + SharedColor color{}; + Float marginTop{0.0}; + Float marginBottom{0.0}; + Float lineHeight{0.0}; + std::string textAlign{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownMarkdownStyleH4Struct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["fontSize"] = fontSize; + result["fontFamily"] = fontFamily; + result["fontWeight"] = fontWeight; + result["color"] = ::facebook::react::toDynamic(color); + result["marginTop"] = marginTop; + result["marginBottom"] = marginBottom; + result["lineHeight"] = lineHeight; + result["textAlign"] = textAlign; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownMarkdownStyleH4Struct &result) { + auto map = (std::unordered_map)value; + + auto tmp_fontSize = map.find("fontSize"); + if (tmp_fontSize != map.end()) { + fromRawValue(context, tmp_fontSize->second, result.fontSize); + } + auto tmp_fontFamily = map.find("fontFamily"); + if (tmp_fontFamily != map.end()) { + fromRawValue(context, tmp_fontFamily->second, result.fontFamily); + } + auto tmp_fontWeight = map.find("fontWeight"); + if (tmp_fontWeight != map.end()) { + fromRawValue(context, tmp_fontWeight->second, result.fontWeight); + } + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } + auto tmp_marginTop = map.find("marginTop"); + if (tmp_marginTop != map.end()) { + fromRawValue(context, tmp_marginTop->second, result.marginTop); + } + auto tmp_marginBottom = map.find("marginBottom"); + if (tmp_marginBottom != map.end()) { + fromRawValue(context, tmp_marginBottom->second, result.marginBottom); + } + auto tmp_lineHeight = map.find("lineHeight"); + if (tmp_lineHeight != map.end()) { + fromRawValue(context, tmp_lineHeight->second, result.lineHeight); + } + auto tmp_textAlign = map.find("textAlign"); + if (tmp_textAlign != map.end()) { + fromRawValue(context, tmp_textAlign->second, result.textAlign); + } +} + +static inline std::string toString(const EnrichedMarkdownMarkdownStyleH4Struct &value) { + return "[Object EnrichedMarkdownMarkdownStyleH4Struct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownMarkdownStyleH4Struct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownMarkdownStyleH5Struct { + Float fontSize{0.0}; + std::string fontFamily{}; + std::string fontWeight{}; + SharedColor color{}; + Float marginTop{0.0}; + Float marginBottom{0.0}; + Float lineHeight{0.0}; + std::string textAlign{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownMarkdownStyleH5Struct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["fontSize"] = fontSize; + result["fontFamily"] = fontFamily; + result["fontWeight"] = fontWeight; + result["color"] = ::facebook::react::toDynamic(color); + result["marginTop"] = marginTop; + result["marginBottom"] = marginBottom; + result["lineHeight"] = lineHeight; + result["textAlign"] = textAlign; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownMarkdownStyleH5Struct &result) { + auto map = (std::unordered_map)value; + + auto tmp_fontSize = map.find("fontSize"); + if (tmp_fontSize != map.end()) { + fromRawValue(context, tmp_fontSize->second, result.fontSize); + } + auto tmp_fontFamily = map.find("fontFamily"); + if (tmp_fontFamily != map.end()) { + fromRawValue(context, tmp_fontFamily->second, result.fontFamily); + } + auto tmp_fontWeight = map.find("fontWeight"); + if (tmp_fontWeight != map.end()) { + fromRawValue(context, tmp_fontWeight->second, result.fontWeight); + } + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } + auto tmp_marginTop = map.find("marginTop"); + if (tmp_marginTop != map.end()) { + fromRawValue(context, tmp_marginTop->second, result.marginTop); + } + auto tmp_marginBottom = map.find("marginBottom"); + if (tmp_marginBottom != map.end()) { + fromRawValue(context, tmp_marginBottom->second, result.marginBottom); + } + auto tmp_lineHeight = map.find("lineHeight"); + if (tmp_lineHeight != map.end()) { + fromRawValue(context, tmp_lineHeight->second, result.lineHeight); + } + auto tmp_textAlign = map.find("textAlign"); + if (tmp_textAlign != map.end()) { + fromRawValue(context, tmp_textAlign->second, result.textAlign); + } +} + +static inline std::string toString(const EnrichedMarkdownMarkdownStyleH5Struct &value) { + return "[Object EnrichedMarkdownMarkdownStyleH5Struct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownMarkdownStyleH5Struct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownMarkdownStyleH6Struct { + Float fontSize{0.0}; + std::string fontFamily{}; + std::string fontWeight{}; + SharedColor color{}; + Float marginTop{0.0}; + Float marginBottom{0.0}; + Float lineHeight{0.0}; + std::string textAlign{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownMarkdownStyleH6Struct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["fontSize"] = fontSize; + result["fontFamily"] = fontFamily; + result["fontWeight"] = fontWeight; + result["color"] = ::facebook::react::toDynamic(color); + result["marginTop"] = marginTop; + result["marginBottom"] = marginBottom; + result["lineHeight"] = lineHeight; + result["textAlign"] = textAlign; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownMarkdownStyleH6Struct &result) { + auto map = (std::unordered_map)value; + + auto tmp_fontSize = map.find("fontSize"); + if (tmp_fontSize != map.end()) { + fromRawValue(context, tmp_fontSize->second, result.fontSize); + } + auto tmp_fontFamily = map.find("fontFamily"); + if (tmp_fontFamily != map.end()) { + fromRawValue(context, tmp_fontFamily->second, result.fontFamily); + } + auto tmp_fontWeight = map.find("fontWeight"); + if (tmp_fontWeight != map.end()) { + fromRawValue(context, tmp_fontWeight->second, result.fontWeight); + } + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } + auto tmp_marginTop = map.find("marginTop"); + if (tmp_marginTop != map.end()) { + fromRawValue(context, tmp_marginTop->second, result.marginTop); + } + auto tmp_marginBottom = map.find("marginBottom"); + if (tmp_marginBottom != map.end()) { + fromRawValue(context, tmp_marginBottom->second, result.marginBottom); + } + auto tmp_lineHeight = map.find("lineHeight"); + if (tmp_lineHeight != map.end()) { + fromRawValue(context, tmp_lineHeight->second, result.lineHeight); + } + auto tmp_textAlign = map.find("textAlign"); + if (tmp_textAlign != map.end()) { + fromRawValue(context, tmp_textAlign->second, result.textAlign); + } +} + +static inline std::string toString(const EnrichedMarkdownMarkdownStyleH6Struct &value) { + return "[Object EnrichedMarkdownMarkdownStyleH6Struct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownMarkdownStyleH6Struct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownMarkdownStyleBlockquoteStruct { + Float fontSize{0.0}; + std::string fontFamily{}; + std::string fontWeight{}; + SharedColor color{}; + Float marginTop{0.0}; + Float marginBottom{0.0}; + Float lineHeight{0.0}; + SharedColor borderColor{}; + Float borderWidth{0.0}; + Float gapWidth{0.0}; + SharedColor backgroundColor{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownMarkdownStyleBlockquoteStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["fontSize"] = fontSize; + result["fontFamily"] = fontFamily; + result["fontWeight"] = fontWeight; + result["color"] = ::facebook::react::toDynamic(color); + result["marginTop"] = marginTop; + result["marginBottom"] = marginBottom; + result["lineHeight"] = lineHeight; + result["borderColor"] = ::facebook::react::toDynamic(borderColor); + result["borderWidth"] = borderWidth; + result["gapWidth"] = gapWidth; + result["backgroundColor"] = ::facebook::react::toDynamic(backgroundColor); + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownMarkdownStyleBlockquoteStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_fontSize = map.find("fontSize"); + if (tmp_fontSize != map.end()) { + fromRawValue(context, tmp_fontSize->second, result.fontSize); + } + auto tmp_fontFamily = map.find("fontFamily"); + if (tmp_fontFamily != map.end()) { + fromRawValue(context, tmp_fontFamily->second, result.fontFamily); + } + auto tmp_fontWeight = map.find("fontWeight"); + if (tmp_fontWeight != map.end()) { + fromRawValue(context, tmp_fontWeight->second, result.fontWeight); + } + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } + auto tmp_marginTop = map.find("marginTop"); + if (tmp_marginTop != map.end()) { + fromRawValue(context, tmp_marginTop->second, result.marginTop); + } + auto tmp_marginBottom = map.find("marginBottom"); + if (tmp_marginBottom != map.end()) { + fromRawValue(context, tmp_marginBottom->second, result.marginBottom); + } + auto tmp_lineHeight = map.find("lineHeight"); + if (tmp_lineHeight != map.end()) { + fromRawValue(context, tmp_lineHeight->second, result.lineHeight); + } + auto tmp_borderColor = map.find("borderColor"); + if (tmp_borderColor != map.end()) { + fromRawValue(context, tmp_borderColor->second, result.borderColor); + } + auto tmp_borderWidth = map.find("borderWidth"); + if (tmp_borderWidth != map.end()) { + fromRawValue(context, tmp_borderWidth->second, result.borderWidth); + } + auto tmp_gapWidth = map.find("gapWidth"); + if (tmp_gapWidth != map.end()) { + fromRawValue(context, tmp_gapWidth->second, result.gapWidth); + } + auto tmp_backgroundColor = map.find("backgroundColor"); + if (tmp_backgroundColor != map.end()) { + fromRawValue(context, tmp_backgroundColor->second, result.backgroundColor); + } +} + +static inline std::string toString(const EnrichedMarkdownMarkdownStyleBlockquoteStruct &value) { + return "[Object EnrichedMarkdownMarkdownStyleBlockquoteStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownMarkdownStyleBlockquoteStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownMarkdownStyleListStruct { + Float fontSize{0.0}; + std::string fontFamily{}; + std::string fontWeight{}; + SharedColor color{}; + Float marginTop{0.0}; + Float marginBottom{0.0}; + Float lineHeight{0.0}; + SharedColor bulletColor{}; + Float bulletSize{0.0}; + Float markerMinWidth{0.0}; + SharedColor markerColor{}; + std::string markerFontWeight{}; + Float gapWidth{0.0}; + Float marginLeft{0.0}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownMarkdownStyleListStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["fontSize"] = fontSize; + result["fontFamily"] = fontFamily; + result["fontWeight"] = fontWeight; + result["color"] = ::facebook::react::toDynamic(color); + result["marginTop"] = marginTop; + result["marginBottom"] = marginBottom; + result["lineHeight"] = lineHeight; + result["bulletColor"] = ::facebook::react::toDynamic(bulletColor); + result["bulletSize"] = bulletSize; + result["markerMinWidth"] = markerMinWidth; + result["markerColor"] = ::facebook::react::toDynamic(markerColor); + result["markerFontWeight"] = markerFontWeight; + result["gapWidth"] = gapWidth; + result["marginLeft"] = marginLeft; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownMarkdownStyleListStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_fontSize = map.find("fontSize"); + if (tmp_fontSize != map.end()) { + fromRawValue(context, tmp_fontSize->second, result.fontSize); + } + auto tmp_fontFamily = map.find("fontFamily"); + if (tmp_fontFamily != map.end()) { + fromRawValue(context, tmp_fontFamily->second, result.fontFamily); + } + auto tmp_fontWeight = map.find("fontWeight"); + if (tmp_fontWeight != map.end()) { + fromRawValue(context, tmp_fontWeight->second, result.fontWeight); + } + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } + auto tmp_marginTop = map.find("marginTop"); + if (tmp_marginTop != map.end()) { + fromRawValue(context, tmp_marginTop->second, result.marginTop); + } + auto tmp_marginBottom = map.find("marginBottom"); + if (tmp_marginBottom != map.end()) { + fromRawValue(context, tmp_marginBottom->second, result.marginBottom); + } + auto tmp_lineHeight = map.find("lineHeight"); + if (tmp_lineHeight != map.end()) { + fromRawValue(context, tmp_lineHeight->second, result.lineHeight); + } + auto tmp_bulletColor = map.find("bulletColor"); + if (tmp_bulletColor != map.end()) { + fromRawValue(context, tmp_bulletColor->second, result.bulletColor); + } + auto tmp_bulletSize = map.find("bulletSize"); + if (tmp_bulletSize != map.end()) { + fromRawValue(context, tmp_bulletSize->second, result.bulletSize); + } + auto tmp_markerMinWidth = map.find("markerMinWidth"); + if (tmp_markerMinWidth != map.end()) { + fromRawValue(context, tmp_markerMinWidth->second, result.markerMinWidth); + } + auto tmp_markerColor = map.find("markerColor"); + if (tmp_markerColor != map.end()) { + fromRawValue(context, tmp_markerColor->second, result.markerColor); + } + auto tmp_markerFontWeight = map.find("markerFontWeight"); + if (tmp_markerFontWeight != map.end()) { + fromRawValue(context, tmp_markerFontWeight->second, result.markerFontWeight); + } + auto tmp_gapWidth = map.find("gapWidth"); + if (tmp_gapWidth != map.end()) { + fromRawValue(context, tmp_gapWidth->second, result.gapWidth); + } + auto tmp_marginLeft = map.find("marginLeft"); + if (tmp_marginLeft != map.end()) { + fromRawValue(context, tmp_marginLeft->second, result.marginLeft); + } +} + +static inline std::string toString(const EnrichedMarkdownMarkdownStyleListStruct &value) { + return "[Object EnrichedMarkdownMarkdownStyleListStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownMarkdownStyleListStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownMarkdownStyleCodeBlockStruct { + Float fontSize{0.0}; + std::string fontFamily{}; + std::string fontWeight{}; + SharedColor color{}; + Float marginTop{0.0}; + Float marginBottom{0.0}; + Float lineHeight{0.0}; + SharedColor backgroundColor{}; + SharedColor borderColor{}; + Float borderRadius{0.0}; + Float borderWidth{0.0}; + Float padding{0.0}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownMarkdownStyleCodeBlockStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["fontSize"] = fontSize; + result["fontFamily"] = fontFamily; + result["fontWeight"] = fontWeight; + result["color"] = ::facebook::react::toDynamic(color); + result["marginTop"] = marginTop; + result["marginBottom"] = marginBottom; + result["lineHeight"] = lineHeight; + result["backgroundColor"] = ::facebook::react::toDynamic(backgroundColor); + result["borderColor"] = ::facebook::react::toDynamic(borderColor); + result["borderRadius"] = borderRadius; + result["borderWidth"] = borderWidth; + result["padding"] = padding; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownMarkdownStyleCodeBlockStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_fontSize = map.find("fontSize"); + if (tmp_fontSize != map.end()) { + fromRawValue(context, tmp_fontSize->second, result.fontSize); + } + auto tmp_fontFamily = map.find("fontFamily"); + if (tmp_fontFamily != map.end()) { + fromRawValue(context, tmp_fontFamily->second, result.fontFamily); + } + auto tmp_fontWeight = map.find("fontWeight"); + if (tmp_fontWeight != map.end()) { + fromRawValue(context, tmp_fontWeight->second, result.fontWeight); + } + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } + auto tmp_marginTop = map.find("marginTop"); + if (tmp_marginTop != map.end()) { + fromRawValue(context, tmp_marginTop->second, result.marginTop); + } + auto tmp_marginBottom = map.find("marginBottom"); + if (tmp_marginBottom != map.end()) { + fromRawValue(context, tmp_marginBottom->second, result.marginBottom); + } + auto tmp_lineHeight = map.find("lineHeight"); + if (tmp_lineHeight != map.end()) { + fromRawValue(context, tmp_lineHeight->second, result.lineHeight); + } + auto tmp_backgroundColor = map.find("backgroundColor"); + if (tmp_backgroundColor != map.end()) { + fromRawValue(context, tmp_backgroundColor->second, result.backgroundColor); + } + auto tmp_borderColor = map.find("borderColor"); + if (tmp_borderColor != map.end()) { + fromRawValue(context, tmp_borderColor->second, result.borderColor); + } + auto tmp_borderRadius = map.find("borderRadius"); + if (tmp_borderRadius != map.end()) { + fromRawValue(context, tmp_borderRadius->second, result.borderRadius); + } + auto tmp_borderWidth = map.find("borderWidth"); + if (tmp_borderWidth != map.end()) { + fromRawValue(context, tmp_borderWidth->second, result.borderWidth); + } + auto tmp_padding = map.find("padding"); + if (tmp_padding != map.end()) { + fromRawValue(context, tmp_padding->second, result.padding); + } +} + +static inline std::string toString(const EnrichedMarkdownMarkdownStyleCodeBlockStruct &value) { + return "[Object EnrichedMarkdownMarkdownStyleCodeBlockStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownMarkdownStyleCodeBlockStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownMarkdownStyleLinkStruct { + std::string fontFamily{}; + SharedColor color{}; + bool underline{false}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownMarkdownStyleLinkStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["fontFamily"] = fontFamily; + result["color"] = ::facebook::react::toDynamic(color); + result["underline"] = underline; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownMarkdownStyleLinkStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_fontFamily = map.find("fontFamily"); + if (tmp_fontFamily != map.end()) { + fromRawValue(context, tmp_fontFamily->second, result.fontFamily); + } + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } + auto tmp_underline = map.find("underline"); + if (tmp_underline != map.end()) { + fromRawValue(context, tmp_underline->second, result.underline); + } +} + +static inline std::string toString(const EnrichedMarkdownMarkdownStyleLinkStruct &value) { + return "[Object EnrichedMarkdownMarkdownStyleLinkStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownMarkdownStyleLinkStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownMarkdownStyleStrongStruct { + std::string fontFamily{}; + std::string fontWeight{}; + SharedColor color{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownMarkdownStyleStrongStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["fontFamily"] = fontFamily; + result["fontWeight"] = fontWeight; + result["color"] = ::facebook::react::toDynamic(color); + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownMarkdownStyleStrongStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_fontFamily = map.find("fontFamily"); + if (tmp_fontFamily != map.end()) { + fromRawValue(context, tmp_fontFamily->second, result.fontFamily); + } + auto tmp_fontWeight = map.find("fontWeight"); + if (tmp_fontWeight != map.end()) { + fromRawValue(context, tmp_fontWeight->second, result.fontWeight); + } + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } +} + +static inline std::string toString(const EnrichedMarkdownMarkdownStyleStrongStruct &value) { + return "[Object EnrichedMarkdownMarkdownStyleStrongStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownMarkdownStyleStrongStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownMarkdownStyleEmStruct { + std::string fontFamily{}; + std::string fontStyle{}; + SharedColor color{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownMarkdownStyleEmStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["fontFamily"] = fontFamily; + result["fontStyle"] = fontStyle; + result["color"] = ::facebook::react::toDynamic(color); + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownMarkdownStyleEmStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_fontFamily = map.find("fontFamily"); + if (tmp_fontFamily != map.end()) { + fromRawValue(context, tmp_fontFamily->second, result.fontFamily); + } + auto tmp_fontStyle = map.find("fontStyle"); + if (tmp_fontStyle != map.end()) { + fromRawValue(context, tmp_fontStyle->second, result.fontStyle); + } + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } +} + +static inline std::string toString(const EnrichedMarkdownMarkdownStyleEmStruct &value) { + return "[Object EnrichedMarkdownMarkdownStyleEmStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownMarkdownStyleEmStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownMarkdownStyleStrikethroughStruct { + SharedColor color{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownMarkdownStyleStrikethroughStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["color"] = ::facebook::react::toDynamic(color); + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownMarkdownStyleStrikethroughStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } +} + +static inline std::string toString(const EnrichedMarkdownMarkdownStyleStrikethroughStruct &value) { + return "[Object EnrichedMarkdownMarkdownStyleStrikethroughStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownMarkdownStyleStrikethroughStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownMarkdownStyleUnderlineStruct { + SharedColor color{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownMarkdownStyleUnderlineStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["color"] = ::facebook::react::toDynamic(color); + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownMarkdownStyleUnderlineStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } +} + +static inline std::string toString(const EnrichedMarkdownMarkdownStyleUnderlineStruct &value) { + return "[Object EnrichedMarkdownMarkdownStyleUnderlineStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownMarkdownStyleUnderlineStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownMarkdownStyleCodeStruct { + std::string fontFamily{}; + Float fontSize{0.0}; + SharedColor color{}; + SharedColor backgroundColor{}; + SharedColor borderColor{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownMarkdownStyleCodeStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["fontFamily"] = fontFamily; + result["fontSize"] = fontSize; + result["color"] = ::facebook::react::toDynamic(color); + result["backgroundColor"] = ::facebook::react::toDynamic(backgroundColor); + result["borderColor"] = ::facebook::react::toDynamic(borderColor); + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownMarkdownStyleCodeStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_fontFamily = map.find("fontFamily"); + if (tmp_fontFamily != map.end()) { + fromRawValue(context, tmp_fontFamily->second, result.fontFamily); + } + auto tmp_fontSize = map.find("fontSize"); + if (tmp_fontSize != map.end()) { + fromRawValue(context, tmp_fontSize->second, result.fontSize); + } + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } + auto tmp_backgroundColor = map.find("backgroundColor"); + if (tmp_backgroundColor != map.end()) { + fromRawValue(context, tmp_backgroundColor->second, result.backgroundColor); + } + auto tmp_borderColor = map.find("borderColor"); + if (tmp_borderColor != map.end()) { + fromRawValue(context, tmp_borderColor->second, result.borderColor); + } +} + +static inline std::string toString(const EnrichedMarkdownMarkdownStyleCodeStruct &value) { + return "[Object EnrichedMarkdownMarkdownStyleCodeStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownMarkdownStyleCodeStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownMarkdownStyleImageStruct { + Float height{0.0}; + Float borderRadius{0.0}; + Float marginTop{0.0}; + Float marginBottom{0.0}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownMarkdownStyleImageStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["height"] = height; + result["borderRadius"] = borderRadius; + result["marginTop"] = marginTop; + result["marginBottom"] = marginBottom; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownMarkdownStyleImageStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_height = map.find("height"); + if (tmp_height != map.end()) { + fromRawValue(context, tmp_height->second, result.height); + } + auto tmp_borderRadius = map.find("borderRadius"); + if (tmp_borderRadius != map.end()) { + fromRawValue(context, tmp_borderRadius->second, result.borderRadius); + } + auto tmp_marginTop = map.find("marginTop"); + if (tmp_marginTop != map.end()) { + fromRawValue(context, tmp_marginTop->second, result.marginTop); + } + auto tmp_marginBottom = map.find("marginBottom"); + if (tmp_marginBottom != map.end()) { + fromRawValue(context, tmp_marginBottom->second, result.marginBottom); + } +} + +static inline std::string toString(const EnrichedMarkdownMarkdownStyleImageStruct &value) { + return "[Object EnrichedMarkdownMarkdownStyleImageStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownMarkdownStyleImageStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownMarkdownStyleInlineImageStruct { + Float size{0.0}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownMarkdownStyleInlineImageStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["size"] = size; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownMarkdownStyleInlineImageStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_size = map.find("size"); + if (tmp_size != map.end()) { + fromRawValue(context, tmp_size->second, result.size); + } +} + +static inline std::string toString(const EnrichedMarkdownMarkdownStyleInlineImageStruct &value) { + return "[Object EnrichedMarkdownMarkdownStyleInlineImageStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownMarkdownStyleInlineImageStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownMarkdownStyleThematicBreakStruct { + SharedColor color{}; + Float height{0.0}; + Float marginTop{0.0}; + Float marginBottom{0.0}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownMarkdownStyleThematicBreakStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["color"] = ::facebook::react::toDynamic(color); + result["height"] = height; + result["marginTop"] = marginTop; + result["marginBottom"] = marginBottom; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownMarkdownStyleThematicBreakStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } + auto tmp_height = map.find("height"); + if (tmp_height != map.end()) { + fromRawValue(context, tmp_height->second, result.height); + } + auto tmp_marginTop = map.find("marginTop"); + if (tmp_marginTop != map.end()) { + fromRawValue(context, tmp_marginTop->second, result.marginTop); + } + auto tmp_marginBottom = map.find("marginBottom"); + if (tmp_marginBottom != map.end()) { + fromRawValue(context, tmp_marginBottom->second, result.marginBottom); + } +} + +static inline std::string toString(const EnrichedMarkdownMarkdownStyleThematicBreakStruct &value) { + return "[Object EnrichedMarkdownMarkdownStyleThematicBreakStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownMarkdownStyleThematicBreakStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownMarkdownStyleTableStruct { + Float fontSize{0.0}; + std::string fontFamily{}; + std::string fontWeight{}; + SharedColor color{}; + Float marginTop{0.0}; + Float marginBottom{0.0}; + Float lineHeight{0.0}; + std::string headerFontFamily{}; + SharedColor headerBackgroundColor{}; + SharedColor headerTextColor{}; + SharedColor rowEvenBackgroundColor{}; + SharedColor rowOddBackgroundColor{}; + SharedColor borderColor{}; + Float borderWidth{0.0}; + Float borderRadius{0.0}; + Float cellPaddingHorizontal{0.0}; + Float cellPaddingVertical{0.0}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownMarkdownStyleTableStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["fontSize"] = fontSize; + result["fontFamily"] = fontFamily; + result["fontWeight"] = fontWeight; + result["color"] = ::facebook::react::toDynamic(color); + result["marginTop"] = marginTop; + result["marginBottom"] = marginBottom; + result["lineHeight"] = lineHeight; + result["headerFontFamily"] = headerFontFamily; + result["headerBackgroundColor"] = ::facebook::react::toDynamic(headerBackgroundColor); + result["headerTextColor"] = ::facebook::react::toDynamic(headerTextColor); + result["rowEvenBackgroundColor"] = ::facebook::react::toDynamic(rowEvenBackgroundColor); + result["rowOddBackgroundColor"] = ::facebook::react::toDynamic(rowOddBackgroundColor); + result["borderColor"] = ::facebook::react::toDynamic(borderColor); + result["borderWidth"] = borderWidth; + result["borderRadius"] = borderRadius; + result["cellPaddingHorizontal"] = cellPaddingHorizontal; + result["cellPaddingVertical"] = cellPaddingVertical; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownMarkdownStyleTableStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_fontSize = map.find("fontSize"); + if (tmp_fontSize != map.end()) { + fromRawValue(context, tmp_fontSize->second, result.fontSize); + } + auto tmp_fontFamily = map.find("fontFamily"); + if (tmp_fontFamily != map.end()) { + fromRawValue(context, tmp_fontFamily->second, result.fontFamily); + } + auto tmp_fontWeight = map.find("fontWeight"); + if (tmp_fontWeight != map.end()) { + fromRawValue(context, tmp_fontWeight->second, result.fontWeight); + } + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } + auto tmp_marginTop = map.find("marginTop"); + if (tmp_marginTop != map.end()) { + fromRawValue(context, tmp_marginTop->second, result.marginTop); + } + auto tmp_marginBottom = map.find("marginBottom"); + if (tmp_marginBottom != map.end()) { + fromRawValue(context, tmp_marginBottom->second, result.marginBottom); + } + auto tmp_lineHeight = map.find("lineHeight"); + if (tmp_lineHeight != map.end()) { + fromRawValue(context, tmp_lineHeight->second, result.lineHeight); + } + auto tmp_headerFontFamily = map.find("headerFontFamily"); + if (tmp_headerFontFamily != map.end()) { + fromRawValue(context, tmp_headerFontFamily->second, result.headerFontFamily); + } + auto tmp_headerBackgroundColor = map.find("headerBackgroundColor"); + if (tmp_headerBackgroundColor != map.end()) { + fromRawValue(context, tmp_headerBackgroundColor->second, result.headerBackgroundColor); + } + auto tmp_headerTextColor = map.find("headerTextColor"); + if (tmp_headerTextColor != map.end()) { + fromRawValue(context, tmp_headerTextColor->second, result.headerTextColor); + } + auto tmp_rowEvenBackgroundColor = map.find("rowEvenBackgroundColor"); + if (tmp_rowEvenBackgroundColor != map.end()) { + fromRawValue(context, tmp_rowEvenBackgroundColor->second, result.rowEvenBackgroundColor); + } + auto tmp_rowOddBackgroundColor = map.find("rowOddBackgroundColor"); + if (tmp_rowOddBackgroundColor != map.end()) { + fromRawValue(context, tmp_rowOddBackgroundColor->second, result.rowOddBackgroundColor); + } + auto tmp_borderColor = map.find("borderColor"); + if (tmp_borderColor != map.end()) { + fromRawValue(context, tmp_borderColor->second, result.borderColor); + } + auto tmp_borderWidth = map.find("borderWidth"); + if (tmp_borderWidth != map.end()) { + fromRawValue(context, tmp_borderWidth->second, result.borderWidth); + } + auto tmp_borderRadius = map.find("borderRadius"); + if (tmp_borderRadius != map.end()) { + fromRawValue(context, tmp_borderRadius->second, result.borderRadius); + } + auto tmp_cellPaddingHorizontal = map.find("cellPaddingHorizontal"); + if (tmp_cellPaddingHorizontal != map.end()) { + fromRawValue(context, tmp_cellPaddingHorizontal->second, result.cellPaddingHorizontal); + } + auto tmp_cellPaddingVertical = map.find("cellPaddingVertical"); + if (tmp_cellPaddingVertical != map.end()) { + fromRawValue(context, tmp_cellPaddingVertical->second, result.cellPaddingVertical); + } +} + +static inline std::string toString(const EnrichedMarkdownMarkdownStyleTableStruct &value) { + return "[Object EnrichedMarkdownMarkdownStyleTableStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownMarkdownStyleTableStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownMarkdownStyleTaskListStruct { + SharedColor checkedColor{}; + SharedColor borderColor{}; + Float checkboxSize{0.0}; + Float checkboxBorderRadius{0.0}; + SharedColor checkmarkColor{}; + SharedColor checkedTextColor{}; + bool checkedStrikethrough{false}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownMarkdownStyleTaskListStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["checkedColor"] = ::facebook::react::toDynamic(checkedColor); + result["borderColor"] = ::facebook::react::toDynamic(borderColor); + result["checkboxSize"] = checkboxSize; + result["checkboxBorderRadius"] = checkboxBorderRadius; + result["checkmarkColor"] = ::facebook::react::toDynamic(checkmarkColor); + result["checkedTextColor"] = ::facebook::react::toDynamic(checkedTextColor); + result["checkedStrikethrough"] = checkedStrikethrough; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownMarkdownStyleTaskListStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_checkedColor = map.find("checkedColor"); + if (tmp_checkedColor != map.end()) { + fromRawValue(context, tmp_checkedColor->second, result.checkedColor); + } + auto tmp_borderColor = map.find("borderColor"); + if (tmp_borderColor != map.end()) { + fromRawValue(context, tmp_borderColor->second, result.borderColor); + } + auto tmp_checkboxSize = map.find("checkboxSize"); + if (tmp_checkboxSize != map.end()) { + fromRawValue(context, tmp_checkboxSize->second, result.checkboxSize); + } + auto tmp_checkboxBorderRadius = map.find("checkboxBorderRadius"); + if (tmp_checkboxBorderRadius != map.end()) { + fromRawValue(context, tmp_checkboxBorderRadius->second, result.checkboxBorderRadius); + } + auto tmp_checkmarkColor = map.find("checkmarkColor"); + if (tmp_checkmarkColor != map.end()) { + fromRawValue(context, tmp_checkmarkColor->second, result.checkmarkColor); + } + auto tmp_checkedTextColor = map.find("checkedTextColor"); + if (tmp_checkedTextColor != map.end()) { + fromRawValue(context, tmp_checkedTextColor->second, result.checkedTextColor); + } + auto tmp_checkedStrikethrough = map.find("checkedStrikethrough"); + if (tmp_checkedStrikethrough != map.end()) { + fromRawValue(context, tmp_checkedStrikethrough->second, result.checkedStrikethrough); + } +} + +static inline std::string toString(const EnrichedMarkdownMarkdownStyleTaskListStruct &value) { + return "[Object EnrichedMarkdownMarkdownStyleTaskListStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownMarkdownStyleTaskListStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownMarkdownStyleMathStruct { + Float fontSize{0.0}; + SharedColor color{}; + SharedColor backgroundColor{}; + Float padding{0.0}; + Float marginTop{0.0}; + Float marginBottom{0.0}; + std::string textAlign{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownMarkdownStyleMathStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["fontSize"] = fontSize; + result["color"] = ::facebook::react::toDynamic(color); + result["backgroundColor"] = ::facebook::react::toDynamic(backgroundColor); + result["padding"] = padding; + result["marginTop"] = marginTop; + result["marginBottom"] = marginBottom; + result["textAlign"] = textAlign; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownMarkdownStyleMathStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_fontSize = map.find("fontSize"); + if (tmp_fontSize != map.end()) { + fromRawValue(context, tmp_fontSize->second, result.fontSize); + } + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } + auto tmp_backgroundColor = map.find("backgroundColor"); + if (tmp_backgroundColor != map.end()) { + fromRawValue(context, tmp_backgroundColor->second, result.backgroundColor); + } + auto tmp_padding = map.find("padding"); + if (tmp_padding != map.end()) { + fromRawValue(context, tmp_padding->second, result.padding); + } + auto tmp_marginTop = map.find("marginTop"); + if (tmp_marginTop != map.end()) { + fromRawValue(context, tmp_marginTop->second, result.marginTop); + } + auto tmp_marginBottom = map.find("marginBottom"); + if (tmp_marginBottom != map.end()) { + fromRawValue(context, tmp_marginBottom->second, result.marginBottom); + } + auto tmp_textAlign = map.find("textAlign"); + if (tmp_textAlign != map.end()) { + fromRawValue(context, tmp_textAlign->second, result.textAlign); + } +} + +static inline std::string toString(const EnrichedMarkdownMarkdownStyleMathStruct &value) { + return "[Object EnrichedMarkdownMarkdownStyleMathStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownMarkdownStyleMathStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownMarkdownStyleInlineMathStruct { + SharedColor color{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownMarkdownStyleInlineMathStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["color"] = ::facebook::react::toDynamic(color); + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownMarkdownStyleInlineMathStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } +} + +static inline std::string toString(const EnrichedMarkdownMarkdownStyleInlineMathStruct &value) { + return "[Object EnrichedMarkdownMarkdownStyleInlineMathStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownMarkdownStyleInlineMathStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownMarkdownStyleSpoilerParticlesStruct { + Float density{0.0}; + Float speed{0.0}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownMarkdownStyleSpoilerParticlesStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["density"] = density; + result["speed"] = speed; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownMarkdownStyleSpoilerParticlesStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_density = map.find("density"); + if (tmp_density != map.end()) { + fromRawValue(context, tmp_density->second, result.density); + } + auto tmp_speed = map.find("speed"); + if (tmp_speed != map.end()) { + fromRawValue(context, tmp_speed->second, result.speed); + } +} + +static inline std::string toString(const EnrichedMarkdownMarkdownStyleSpoilerParticlesStruct &value) { + return "[Object EnrichedMarkdownMarkdownStyleSpoilerParticlesStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownMarkdownStyleSpoilerParticlesStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownMarkdownStyleSpoilerSolidStruct { + Float borderRadius{0.0}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownMarkdownStyleSpoilerSolidStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["borderRadius"] = borderRadius; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownMarkdownStyleSpoilerSolidStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_borderRadius = map.find("borderRadius"); + if (tmp_borderRadius != map.end()) { + fromRawValue(context, tmp_borderRadius->second, result.borderRadius); + } +} + +static inline std::string toString(const EnrichedMarkdownMarkdownStyleSpoilerSolidStruct &value) { + return "[Object EnrichedMarkdownMarkdownStyleSpoilerSolidStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownMarkdownStyleSpoilerSolidStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownMarkdownStyleSpoilerStruct { + SharedColor color{}; + EnrichedMarkdownMarkdownStyleSpoilerParticlesStruct particles{}; + EnrichedMarkdownMarkdownStyleSpoilerSolidStruct solid{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownMarkdownStyleSpoilerStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["color"] = ::facebook::react::toDynamic(color); + result["particles"] = ::facebook::react::toDynamic(particles); + result["solid"] = ::facebook::react::toDynamic(solid); + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownMarkdownStyleSpoilerStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } + auto tmp_particles = map.find("particles"); + if (tmp_particles != map.end()) { + fromRawValue(context, tmp_particles->second, result.particles); + } + auto tmp_solid = map.find("solid"); + if (tmp_solid != map.end()) { + fromRawValue(context, tmp_solid->second, result.solid); + } +} + +static inline std::string toString(const EnrichedMarkdownMarkdownStyleSpoilerStruct &value) { + return "[Object EnrichedMarkdownMarkdownStyleSpoilerStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownMarkdownStyleSpoilerStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownMarkdownStyleMentionStruct { + SharedColor color{}; + SharedColor backgroundColor{}; + SharedColor borderColor{}; + Float borderWidth{0.0}; + Float borderRadius{0.0}; + Float paddingHorizontal{0.0}; + Float paddingVertical{0.0}; + std::string fontFamily{}; + std::string fontWeight{}; + Float fontSize{0.0}; + Float pressedOpacity{0.0}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownMarkdownStyleMentionStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["color"] = ::facebook::react::toDynamic(color); + result["backgroundColor"] = ::facebook::react::toDynamic(backgroundColor); + result["borderColor"] = ::facebook::react::toDynamic(borderColor); + result["borderWidth"] = borderWidth; + result["borderRadius"] = borderRadius; + result["paddingHorizontal"] = paddingHorizontal; + result["paddingVertical"] = paddingVertical; + result["fontFamily"] = fontFamily; + result["fontWeight"] = fontWeight; + result["fontSize"] = fontSize; + result["pressedOpacity"] = pressedOpacity; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownMarkdownStyleMentionStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } + auto tmp_backgroundColor = map.find("backgroundColor"); + if (tmp_backgroundColor != map.end()) { + fromRawValue(context, tmp_backgroundColor->second, result.backgroundColor); + } + auto tmp_borderColor = map.find("borderColor"); + if (tmp_borderColor != map.end()) { + fromRawValue(context, tmp_borderColor->second, result.borderColor); + } + auto tmp_borderWidth = map.find("borderWidth"); + if (tmp_borderWidth != map.end()) { + fromRawValue(context, tmp_borderWidth->second, result.borderWidth); + } + auto tmp_borderRadius = map.find("borderRadius"); + if (tmp_borderRadius != map.end()) { + fromRawValue(context, tmp_borderRadius->second, result.borderRadius); + } + auto tmp_paddingHorizontal = map.find("paddingHorizontal"); + if (tmp_paddingHorizontal != map.end()) { + fromRawValue(context, tmp_paddingHorizontal->second, result.paddingHorizontal); + } + auto tmp_paddingVertical = map.find("paddingVertical"); + if (tmp_paddingVertical != map.end()) { + fromRawValue(context, tmp_paddingVertical->second, result.paddingVertical); + } + auto tmp_fontFamily = map.find("fontFamily"); + if (tmp_fontFamily != map.end()) { + fromRawValue(context, tmp_fontFamily->second, result.fontFamily); + } + auto tmp_fontWeight = map.find("fontWeight"); + if (tmp_fontWeight != map.end()) { + fromRawValue(context, tmp_fontWeight->second, result.fontWeight); + } + auto tmp_fontSize = map.find("fontSize"); + if (tmp_fontSize != map.end()) { + fromRawValue(context, tmp_fontSize->second, result.fontSize); + } + auto tmp_pressedOpacity = map.find("pressedOpacity"); + if (tmp_pressedOpacity != map.end()) { + fromRawValue(context, tmp_pressedOpacity->second, result.pressedOpacity); + } +} + +static inline std::string toString(const EnrichedMarkdownMarkdownStyleMentionStruct &value) { + return "[Object EnrichedMarkdownMarkdownStyleMentionStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownMarkdownStyleMentionStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownMarkdownStyleCitationStruct { + SharedColor color{}; + Float fontSizeMultiplier{0.0}; + Float baselineOffsetPx{0.0}; + std::string fontWeight{}; + bool underline{false}; + SharedColor backgroundColor{}; + Float paddingHorizontal{0.0}; + Float paddingVertical{0.0}; + SharedColor borderColor{}; + Float borderWidth{0.0}; + Float borderRadius{0.0}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownMarkdownStyleCitationStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["color"] = ::facebook::react::toDynamic(color); + result["fontSizeMultiplier"] = fontSizeMultiplier; + result["baselineOffsetPx"] = baselineOffsetPx; + result["fontWeight"] = fontWeight; + result["underline"] = underline; + result["backgroundColor"] = ::facebook::react::toDynamic(backgroundColor); + result["paddingHorizontal"] = paddingHorizontal; + result["paddingVertical"] = paddingVertical; + result["borderColor"] = ::facebook::react::toDynamic(borderColor); + result["borderWidth"] = borderWidth; + result["borderRadius"] = borderRadius; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownMarkdownStyleCitationStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } + auto tmp_fontSizeMultiplier = map.find("fontSizeMultiplier"); + if (tmp_fontSizeMultiplier != map.end()) { + fromRawValue(context, tmp_fontSizeMultiplier->second, result.fontSizeMultiplier); + } + auto tmp_baselineOffsetPx = map.find("baselineOffsetPx"); + if (tmp_baselineOffsetPx != map.end()) { + fromRawValue(context, tmp_baselineOffsetPx->second, result.baselineOffsetPx); + } + auto tmp_fontWeight = map.find("fontWeight"); + if (tmp_fontWeight != map.end()) { + fromRawValue(context, tmp_fontWeight->second, result.fontWeight); + } + auto tmp_underline = map.find("underline"); + if (tmp_underline != map.end()) { + fromRawValue(context, tmp_underline->second, result.underline); + } + auto tmp_backgroundColor = map.find("backgroundColor"); + if (tmp_backgroundColor != map.end()) { + fromRawValue(context, tmp_backgroundColor->second, result.backgroundColor); + } + auto tmp_paddingHorizontal = map.find("paddingHorizontal"); + if (tmp_paddingHorizontal != map.end()) { + fromRawValue(context, tmp_paddingHorizontal->second, result.paddingHorizontal); + } + auto tmp_paddingVertical = map.find("paddingVertical"); + if (tmp_paddingVertical != map.end()) { + fromRawValue(context, tmp_paddingVertical->second, result.paddingVertical); + } + auto tmp_borderColor = map.find("borderColor"); + if (tmp_borderColor != map.end()) { + fromRawValue(context, tmp_borderColor->second, result.borderColor); + } + auto tmp_borderWidth = map.find("borderWidth"); + if (tmp_borderWidth != map.end()) { + fromRawValue(context, tmp_borderWidth->second, result.borderWidth); + } + auto tmp_borderRadius = map.find("borderRadius"); + if (tmp_borderRadius != map.end()) { + fromRawValue(context, tmp_borderRadius->second, result.borderRadius); + } +} + +static inline std::string toString(const EnrichedMarkdownMarkdownStyleCitationStruct &value) { + return "[Object EnrichedMarkdownMarkdownStyleCitationStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownMarkdownStyleCitationStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownMarkdownStyleStruct { + EnrichedMarkdownMarkdownStyleParagraphStruct paragraph{}; + EnrichedMarkdownMarkdownStyleH1Struct h1{}; + EnrichedMarkdownMarkdownStyleH2Struct h2{}; + EnrichedMarkdownMarkdownStyleH3Struct h3{}; + EnrichedMarkdownMarkdownStyleH4Struct h4{}; + EnrichedMarkdownMarkdownStyleH5Struct h5{}; + EnrichedMarkdownMarkdownStyleH6Struct h6{}; + EnrichedMarkdownMarkdownStyleBlockquoteStruct blockquote{}; + EnrichedMarkdownMarkdownStyleListStruct list{}; + EnrichedMarkdownMarkdownStyleCodeBlockStruct codeBlock{}; + EnrichedMarkdownMarkdownStyleLinkStruct link{}; + EnrichedMarkdownMarkdownStyleStrongStruct strong{}; + EnrichedMarkdownMarkdownStyleEmStruct em{}; + EnrichedMarkdownMarkdownStyleStrikethroughStruct strikethrough{}; + EnrichedMarkdownMarkdownStyleUnderlineStruct underline{}; + EnrichedMarkdownMarkdownStyleCodeStruct code{}; + EnrichedMarkdownMarkdownStyleImageStruct image{}; + EnrichedMarkdownMarkdownStyleInlineImageStruct inlineImage{}; + EnrichedMarkdownMarkdownStyleThematicBreakStruct thematicBreak{}; + EnrichedMarkdownMarkdownStyleTableStruct table{}; + EnrichedMarkdownMarkdownStyleTaskListStruct taskList{}; + EnrichedMarkdownMarkdownStyleMathStruct math{}; + EnrichedMarkdownMarkdownStyleInlineMathStruct inlineMath{}; + EnrichedMarkdownMarkdownStyleSpoilerStruct spoiler{}; + EnrichedMarkdownMarkdownStyleMentionStruct mention{}; + EnrichedMarkdownMarkdownStyleCitationStruct citation{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownMarkdownStyleStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["paragraph"] = ::facebook::react::toDynamic(paragraph); + result["h1"] = ::facebook::react::toDynamic(h1); + result["h2"] = ::facebook::react::toDynamic(h2); + result["h3"] = ::facebook::react::toDynamic(h3); + result["h4"] = ::facebook::react::toDynamic(h4); + result["h5"] = ::facebook::react::toDynamic(h5); + result["h6"] = ::facebook::react::toDynamic(h6); + result["blockquote"] = ::facebook::react::toDynamic(blockquote); + result["list"] = ::facebook::react::toDynamic(list); + result["codeBlock"] = ::facebook::react::toDynamic(codeBlock); + result["link"] = ::facebook::react::toDynamic(link); + result["strong"] = ::facebook::react::toDynamic(strong); + result["em"] = ::facebook::react::toDynamic(em); + result["strikethrough"] = ::facebook::react::toDynamic(strikethrough); + result["underline"] = ::facebook::react::toDynamic(underline); + result["code"] = ::facebook::react::toDynamic(code); + result["image"] = ::facebook::react::toDynamic(image); + result["inlineImage"] = ::facebook::react::toDynamic(inlineImage); + result["thematicBreak"] = ::facebook::react::toDynamic(thematicBreak); + result["table"] = ::facebook::react::toDynamic(table); + result["taskList"] = ::facebook::react::toDynamic(taskList); + result["math"] = ::facebook::react::toDynamic(math); + result["inlineMath"] = ::facebook::react::toDynamic(inlineMath); + result["spoiler"] = ::facebook::react::toDynamic(spoiler); + result["mention"] = ::facebook::react::toDynamic(mention); + result["citation"] = ::facebook::react::toDynamic(citation); + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownMarkdownStyleStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_paragraph = map.find("paragraph"); + if (tmp_paragraph != map.end()) { + fromRawValue(context, tmp_paragraph->second, result.paragraph); + } + auto tmp_h1 = map.find("h1"); + if (tmp_h1 != map.end()) { + fromRawValue(context, tmp_h1->second, result.h1); + } + auto tmp_h2 = map.find("h2"); + if (tmp_h2 != map.end()) { + fromRawValue(context, tmp_h2->second, result.h2); + } + auto tmp_h3 = map.find("h3"); + if (tmp_h3 != map.end()) { + fromRawValue(context, tmp_h3->second, result.h3); + } + auto tmp_h4 = map.find("h4"); + if (tmp_h4 != map.end()) { + fromRawValue(context, tmp_h4->second, result.h4); + } + auto tmp_h5 = map.find("h5"); + if (tmp_h5 != map.end()) { + fromRawValue(context, tmp_h5->second, result.h5); + } + auto tmp_h6 = map.find("h6"); + if (tmp_h6 != map.end()) { + fromRawValue(context, tmp_h6->second, result.h6); + } + auto tmp_blockquote = map.find("blockquote"); + if (tmp_blockquote != map.end()) { + fromRawValue(context, tmp_blockquote->second, result.blockquote); + } + auto tmp_list = map.find("list"); + if (tmp_list != map.end()) { + fromRawValue(context, tmp_list->second, result.list); + } + auto tmp_codeBlock = map.find("codeBlock"); + if (tmp_codeBlock != map.end()) { + fromRawValue(context, tmp_codeBlock->second, result.codeBlock); + } + auto tmp_link = map.find("link"); + if (tmp_link != map.end()) { + fromRawValue(context, tmp_link->second, result.link); + } + auto tmp_strong = map.find("strong"); + if (tmp_strong != map.end()) { + fromRawValue(context, tmp_strong->second, result.strong); + } + auto tmp_em = map.find("em"); + if (tmp_em != map.end()) { + fromRawValue(context, tmp_em->second, result.em); + } + auto tmp_strikethrough = map.find("strikethrough"); + if (tmp_strikethrough != map.end()) { + fromRawValue(context, tmp_strikethrough->second, result.strikethrough); + } + auto tmp_underline = map.find("underline"); + if (tmp_underline != map.end()) { + fromRawValue(context, tmp_underline->second, result.underline); + } + auto tmp_code = map.find("code"); + if (tmp_code != map.end()) { + fromRawValue(context, tmp_code->second, result.code); + } + auto tmp_image = map.find("image"); + if (tmp_image != map.end()) { + fromRawValue(context, tmp_image->second, result.image); + } + auto tmp_inlineImage = map.find("inlineImage"); + if (tmp_inlineImage != map.end()) { + fromRawValue(context, tmp_inlineImage->second, result.inlineImage); + } + auto tmp_thematicBreak = map.find("thematicBreak"); + if (tmp_thematicBreak != map.end()) { + fromRawValue(context, tmp_thematicBreak->second, result.thematicBreak); + } + auto tmp_table = map.find("table"); + if (tmp_table != map.end()) { + fromRawValue(context, tmp_table->second, result.table); + } + auto tmp_taskList = map.find("taskList"); + if (tmp_taskList != map.end()) { + fromRawValue(context, tmp_taskList->second, result.taskList); + } + auto tmp_math = map.find("math"); + if (tmp_math != map.end()) { + fromRawValue(context, tmp_math->second, result.math); + } + auto tmp_inlineMath = map.find("inlineMath"); + if (tmp_inlineMath != map.end()) { + fromRawValue(context, tmp_inlineMath->second, result.inlineMath); + } + auto tmp_spoiler = map.find("spoiler"); + if (tmp_spoiler != map.end()) { + fromRawValue(context, tmp_spoiler->second, result.spoiler); + } + auto tmp_mention = map.find("mention"); + if (tmp_mention != map.end()) { + fromRawValue(context, tmp_mention->second, result.mention); + } + auto tmp_citation = map.find("citation"); + if (tmp_citation != map.end()) { + fromRawValue(context, tmp_citation->second, result.citation); + } +} + +static inline std::string toString(const EnrichedMarkdownMarkdownStyleStruct &value) { + return "[Object EnrichedMarkdownMarkdownStyleStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownMarkdownStyleStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownMd4cFlagsStruct { + bool underline{false}; + bool latexMath{false}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownMd4cFlagsStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["underline"] = underline; + result["latexMath"] = latexMath; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownMd4cFlagsStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_underline = map.find("underline"); + if (tmp_underline != map.end()) { + fromRawValue(context, tmp_underline->second, result.underline); + } + auto tmp_latexMath = map.find("latexMath"); + if (tmp_latexMath != map.end()) { + fromRawValue(context, tmp_latexMath->second, result.latexMath); + } +} + +static inline std::string toString(const EnrichedMarkdownMd4cFlagsStruct &value) { + return "[Object EnrichedMarkdownMd4cFlagsStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownMd4cFlagsStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownContextMenuItemsStruct { + std::string text{}; + std::string icon{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownContextMenuItemsStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["text"] = text; + result["icon"] = icon; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownContextMenuItemsStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_text = map.find("text"); + if (tmp_text != map.end()) { + fromRawValue(context, tmp_text->second, result.text); + } + auto tmp_icon = map.find("icon"); + if (tmp_icon != map.end()) { + fromRawValue(context, tmp_icon->second, result.icon); + } +} + +static inline std::string toString(const EnrichedMarkdownContextMenuItemsStruct &value) { + return "[Object EnrichedMarkdownContextMenuItemsStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownContextMenuItemsStruct &value) { + return value.toDynamic(); +} +#endif + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, std::vector &result) { + auto items = (std::vector)value; + for (const auto &item : items) { + EnrichedMarkdownContextMenuItemsStruct newItem; + fromRawValue(context, item, newItem); + result.emplace_back(newItem); + } +} + +class EnrichedMarkdownProps final : public ViewProps { + public: + EnrichedMarkdownProps() = default; + EnrichedMarkdownProps(const PropsParserContext& context, const EnrichedMarkdownProps &sourceProps, const RawProps &rawProps); + +#pragma mark - Props + + std::string markdown{}; + EnrichedMarkdownMarkdownStyleStruct markdownStyle{}; + bool enableLinkPreview{true}; + bool selectable{false}; + SharedColor selectionColor{}; + SharedColor selectionHandleColor{}; + EnrichedMarkdownMd4cFlagsStruct md4cFlags{}; + bool allowFontScaling{true}; + Float maxFontSizeMultiplier{0.0}; + bool allowTrailingMargin{false}; + bool streamingAnimation{false}; + std::string spoilerOverlay{std::string{"particles"}}; + std::vector contextMenuItems{}; + + #ifdef RN_SERIALIZABLE_STATE + ComponentName getDiffPropsImplementationTarget() const override; + + folly::dynamic getDiffProps(const Props* prevProps) const override; + #endif + + +}; + +struct EnrichedMarkdownTextInputMarkdownStyleStrongStruct { + SharedColor color{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownTextInputMarkdownStyleStrongStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["color"] = ::facebook::react::toDynamic(color); + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownTextInputMarkdownStyleStrongStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } +} + +static inline std::string toString(const EnrichedMarkdownTextInputMarkdownStyleStrongStruct &value) { + return "[Object EnrichedMarkdownTextInputMarkdownStyleStrongStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownTextInputMarkdownStyleStrongStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownTextInputMarkdownStyleEmStruct { + SharedColor color{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownTextInputMarkdownStyleEmStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["color"] = ::facebook::react::toDynamic(color); + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownTextInputMarkdownStyleEmStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } +} + +static inline std::string toString(const EnrichedMarkdownTextInputMarkdownStyleEmStruct &value) { + return "[Object EnrichedMarkdownTextInputMarkdownStyleEmStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownTextInputMarkdownStyleEmStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownTextInputMarkdownStyleLinkStruct { + SharedColor color{}; + bool underline{false}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownTextInputMarkdownStyleLinkStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["color"] = ::facebook::react::toDynamic(color); + result["underline"] = underline; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownTextInputMarkdownStyleLinkStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } + auto tmp_underline = map.find("underline"); + if (tmp_underline != map.end()) { + fromRawValue(context, tmp_underline->second, result.underline); + } +} + +static inline std::string toString(const EnrichedMarkdownTextInputMarkdownStyleLinkStruct &value) { + return "[Object EnrichedMarkdownTextInputMarkdownStyleLinkStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownTextInputMarkdownStyleLinkStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownTextInputMarkdownStyleSpoilerStruct { + SharedColor color{}; + SharedColor backgroundColor{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownTextInputMarkdownStyleSpoilerStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["color"] = ::facebook::react::toDynamic(color); + result["backgroundColor"] = ::facebook::react::toDynamic(backgroundColor); + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownTextInputMarkdownStyleSpoilerStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } + auto tmp_backgroundColor = map.find("backgroundColor"); + if (tmp_backgroundColor != map.end()) { + fromRawValue(context, tmp_backgroundColor->second, result.backgroundColor); + } +} + +static inline std::string toString(const EnrichedMarkdownTextInputMarkdownStyleSpoilerStruct &value) { + return "[Object EnrichedMarkdownTextInputMarkdownStyleSpoilerStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownTextInputMarkdownStyleSpoilerStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownTextInputMarkdownStyleStruct { + EnrichedMarkdownTextInputMarkdownStyleStrongStruct strong{}; + EnrichedMarkdownTextInputMarkdownStyleEmStruct em{}; + EnrichedMarkdownTextInputMarkdownStyleLinkStruct link{}; + EnrichedMarkdownTextInputMarkdownStyleSpoilerStruct spoiler{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownTextInputMarkdownStyleStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["strong"] = ::facebook::react::toDynamic(strong); + result["em"] = ::facebook::react::toDynamic(em); + result["link"] = ::facebook::react::toDynamic(link); + result["spoiler"] = ::facebook::react::toDynamic(spoiler); + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownTextInputMarkdownStyleStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_strong = map.find("strong"); + if (tmp_strong != map.end()) { + fromRawValue(context, tmp_strong->second, result.strong); + } + auto tmp_em = map.find("em"); + if (tmp_em != map.end()) { + fromRawValue(context, tmp_em->second, result.em); + } + auto tmp_link = map.find("link"); + if (tmp_link != map.end()) { + fromRawValue(context, tmp_link->second, result.link); + } + auto tmp_spoiler = map.find("spoiler"); + if (tmp_spoiler != map.end()) { + fromRawValue(context, tmp_spoiler->second, result.spoiler); + } +} + +static inline std::string toString(const EnrichedMarkdownTextInputMarkdownStyleStruct &value) { + return "[Object EnrichedMarkdownTextInputMarkdownStyleStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownTextInputMarkdownStyleStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownTextInputContextMenuItemsStruct { + std::string text{}; + std::string icon{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownTextInputContextMenuItemsStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["text"] = text; + result["icon"] = icon; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownTextInputContextMenuItemsStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_text = map.find("text"); + if (tmp_text != map.end()) { + fromRawValue(context, tmp_text->second, result.text); + } + auto tmp_icon = map.find("icon"); + if (tmp_icon != map.end()) { + fromRawValue(context, tmp_icon->second, result.icon); + } +} + +static inline std::string toString(const EnrichedMarkdownTextInputContextMenuItemsStruct &value) { + return "[Object EnrichedMarkdownTextInputContextMenuItemsStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownTextInputContextMenuItemsStruct &value) { + return value.toDynamic(); +} +#endif + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, std::vector &result) { + auto items = (std::vector)value; + for (const auto &item : items) { + EnrichedMarkdownTextInputContextMenuItemsStruct newItem; + fromRawValue(context, item, newItem); + result.emplace_back(newItem); + } +} + + +struct EnrichedMarkdownTextInputLinkRegexStruct { + std::string pattern{}; + bool caseInsensitive{false}; + bool dotAll{false}; + bool isDisabled{false}; + bool isDefault{false}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownTextInputLinkRegexStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["pattern"] = pattern; + result["caseInsensitive"] = caseInsensitive; + result["dotAll"] = dotAll; + result["isDisabled"] = isDisabled; + result["isDefault"] = isDefault; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownTextInputLinkRegexStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_pattern = map.find("pattern"); + if (tmp_pattern != map.end()) { + fromRawValue(context, tmp_pattern->second, result.pattern); + } + auto tmp_caseInsensitive = map.find("caseInsensitive"); + if (tmp_caseInsensitive != map.end()) { + fromRawValue(context, tmp_caseInsensitive->second, result.caseInsensitive); + } + auto tmp_dotAll = map.find("dotAll"); + if (tmp_dotAll != map.end()) { + fromRawValue(context, tmp_dotAll->second, result.dotAll); + } + auto tmp_isDisabled = map.find("isDisabled"); + if (tmp_isDisabled != map.end()) { + fromRawValue(context, tmp_isDisabled->second, result.isDisabled); + } + auto tmp_isDefault = map.find("isDefault"); + if (tmp_isDefault != map.end()) { + fromRawValue(context, tmp_isDefault->second, result.isDefault); + } +} + +static inline std::string toString(const EnrichedMarkdownTextInputLinkRegexStruct &value) { + return "[Object EnrichedMarkdownTextInputLinkRegexStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownTextInputLinkRegexStruct &value) { + return value.toDynamic(); +} +#endif +class EnrichedMarkdownTextInputProps final : public ViewProps { + public: + EnrichedMarkdownTextInputProps() = default; + EnrichedMarkdownTextInputProps(const PropsParserContext& context, const EnrichedMarkdownTextInputProps &sourceProps, const RawProps &rawProps); + +#pragma mark - Props + + std::string defaultValue{}; + std::string placeholder{}; + SharedColor placeholderTextColor{}; + bool editable{false}; + bool autoFocus{false}; + bool scrollEnabled{false}; + std::string autoCapitalize{}; + bool multiline{false}; + SharedColor cursorColor{}; + SharedColor selectionColor{}; + EnrichedMarkdownTextInputMarkdownStyleStruct markdownStyle{}; + SharedColor color{}; + Float fontSize{0.0}; + Float lineHeight{0.0}; + std::string fontFamily{}; + std::string fontWeight{}; + bool isOnChangeMarkdownSet{false}; + std::vector contextMenuItems{}; + EnrichedMarkdownTextInputLinkRegexStruct linkRegex{}; + + #ifdef RN_SERIALIZABLE_STATE + ComponentName getDiffPropsImplementationTarget() const override; + + folly::dynamic getDiffProps(const Props* prevProps) const override; + #endif + + +}; + +struct EnrichedMarkdownTextMarkdownStyleParagraphStruct { + Float fontSize{0.0}; + std::string fontFamily{}; + std::string fontWeight{}; + SharedColor color{}; + Float marginTop{0.0}; + Float marginBottom{0.0}; + Float lineHeight{0.0}; + std::string textAlign{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownTextMarkdownStyleParagraphStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["fontSize"] = fontSize; + result["fontFamily"] = fontFamily; + result["fontWeight"] = fontWeight; + result["color"] = ::facebook::react::toDynamic(color); + result["marginTop"] = marginTop; + result["marginBottom"] = marginBottom; + result["lineHeight"] = lineHeight; + result["textAlign"] = textAlign; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownTextMarkdownStyleParagraphStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_fontSize = map.find("fontSize"); + if (tmp_fontSize != map.end()) { + fromRawValue(context, tmp_fontSize->second, result.fontSize); + } + auto tmp_fontFamily = map.find("fontFamily"); + if (tmp_fontFamily != map.end()) { + fromRawValue(context, tmp_fontFamily->second, result.fontFamily); + } + auto tmp_fontWeight = map.find("fontWeight"); + if (tmp_fontWeight != map.end()) { + fromRawValue(context, tmp_fontWeight->second, result.fontWeight); + } + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } + auto tmp_marginTop = map.find("marginTop"); + if (tmp_marginTop != map.end()) { + fromRawValue(context, tmp_marginTop->second, result.marginTop); + } + auto tmp_marginBottom = map.find("marginBottom"); + if (tmp_marginBottom != map.end()) { + fromRawValue(context, tmp_marginBottom->second, result.marginBottom); + } + auto tmp_lineHeight = map.find("lineHeight"); + if (tmp_lineHeight != map.end()) { + fromRawValue(context, tmp_lineHeight->second, result.lineHeight); + } + auto tmp_textAlign = map.find("textAlign"); + if (tmp_textAlign != map.end()) { + fromRawValue(context, tmp_textAlign->second, result.textAlign); + } +} + +static inline std::string toString(const EnrichedMarkdownTextMarkdownStyleParagraphStruct &value) { + return "[Object EnrichedMarkdownTextMarkdownStyleParagraphStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownTextMarkdownStyleParagraphStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownTextMarkdownStyleH1Struct { + Float fontSize{0.0}; + std::string fontFamily{}; + std::string fontWeight{}; + SharedColor color{}; + Float marginTop{0.0}; + Float marginBottom{0.0}; + Float lineHeight{0.0}; + std::string textAlign{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownTextMarkdownStyleH1Struct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["fontSize"] = fontSize; + result["fontFamily"] = fontFamily; + result["fontWeight"] = fontWeight; + result["color"] = ::facebook::react::toDynamic(color); + result["marginTop"] = marginTop; + result["marginBottom"] = marginBottom; + result["lineHeight"] = lineHeight; + result["textAlign"] = textAlign; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownTextMarkdownStyleH1Struct &result) { + auto map = (std::unordered_map)value; + + auto tmp_fontSize = map.find("fontSize"); + if (tmp_fontSize != map.end()) { + fromRawValue(context, tmp_fontSize->second, result.fontSize); + } + auto tmp_fontFamily = map.find("fontFamily"); + if (tmp_fontFamily != map.end()) { + fromRawValue(context, tmp_fontFamily->second, result.fontFamily); + } + auto tmp_fontWeight = map.find("fontWeight"); + if (tmp_fontWeight != map.end()) { + fromRawValue(context, tmp_fontWeight->second, result.fontWeight); + } + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } + auto tmp_marginTop = map.find("marginTop"); + if (tmp_marginTop != map.end()) { + fromRawValue(context, tmp_marginTop->second, result.marginTop); + } + auto tmp_marginBottom = map.find("marginBottom"); + if (tmp_marginBottom != map.end()) { + fromRawValue(context, tmp_marginBottom->second, result.marginBottom); + } + auto tmp_lineHeight = map.find("lineHeight"); + if (tmp_lineHeight != map.end()) { + fromRawValue(context, tmp_lineHeight->second, result.lineHeight); + } + auto tmp_textAlign = map.find("textAlign"); + if (tmp_textAlign != map.end()) { + fromRawValue(context, tmp_textAlign->second, result.textAlign); + } +} + +static inline std::string toString(const EnrichedMarkdownTextMarkdownStyleH1Struct &value) { + return "[Object EnrichedMarkdownTextMarkdownStyleH1Struct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownTextMarkdownStyleH1Struct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownTextMarkdownStyleH2Struct { + Float fontSize{0.0}; + std::string fontFamily{}; + std::string fontWeight{}; + SharedColor color{}; + Float marginTop{0.0}; + Float marginBottom{0.0}; + Float lineHeight{0.0}; + std::string textAlign{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownTextMarkdownStyleH2Struct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["fontSize"] = fontSize; + result["fontFamily"] = fontFamily; + result["fontWeight"] = fontWeight; + result["color"] = ::facebook::react::toDynamic(color); + result["marginTop"] = marginTop; + result["marginBottom"] = marginBottom; + result["lineHeight"] = lineHeight; + result["textAlign"] = textAlign; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownTextMarkdownStyleH2Struct &result) { + auto map = (std::unordered_map)value; + + auto tmp_fontSize = map.find("fontSize"); + if (tmp_fontSize != map.end()) { + fromRawValue(context, tmp_fontSize->second, result.fontSize); + } + auto tmp_fontFamily = map.find("fontFamily"); + if (tmp_fontFamily != map.end()) { + fromRawValue(context, tmp_fontFamily->second, result.fontFamily); + } + auto tmp_fontWeight = map.find("fontWeight"); + if (tmp_fontWeight != map.end()) { + fromRawValue(context, tmp_fontWeight->second, result.fontWeight); + } + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } + auto tmp_marginTop = map.find("marginTop"); + if (tmp_marginTop != map.end()) { + fromRawValue(context, tmp_marginTop->second, result.marginTop); + } + auto tmp_marginBottom = map.find("marginBottom"); + if (tmp_marginBottom != map.end()) { + fromRawValue(context, tmp_marginBottom->second, result.marginBottom); + } + auto tmp_lineHeight = map.find("lineHeight"); + if (tmp_lineHeight != map.end()) { + fromRawValue(context, tmp_lineHeight->second, result.lineHeight); + } + auto tmp_textAlign = map.find("textAlign"); + if (tmp_textAlign != map.end()) { + fromRawValue(context, tmp_textAlign->second, result.textAlign); + } +} + +static inline std::string toString(const EnrichedMarkdownTextMarkdownStyleH2Struct &value) { + return "[Object EnrichedMarkdownTextMarkdownStyleH2Struct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownTextMarkdownStyleH2Struct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownTextMarkdownStyleH3Struct { + Float fontSize{0.0}; + std::string fontFamily{}; + std::string fontWeight{}; + SharedColor color{}; + Float marginTop{0.0}; + Float marginBottom{0.0}; + Float lineHeight{0.0}; + std::string textAlign{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownTextMarkdownStyleH3Struct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["fontSize"] = fontSize; + result["fontFamily"] = fontFamily; + result["fontWeight"] = fontWeight; + result["color"] = ::facebook::react::toDynamic(color); + result["marginTop"] = marginTop; + result["marginBottom"] = marginBottom; + result["lineHeight"] = lineHeight; + result["textAlign"] = textAlign; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownTextMarkdownStyleH3Struct &result) { + auto map = (std::unordered_map)value; + + auto tmp_fontSize = map.find("fontSize"); + if (tmp_fontSize != map.end()) { + fromRawValue(context, tmp_fontSize->second, result.fontSize); + } + auto tmp_fontFamily = map.find("fontFamily"); + if (tmp_fontFamily != map.end()) { + fromRawValue(context, tmp_fontFamily->second, result.fontFamily); + } + auto tmp_fontWeight = map.find("fontWeight"); + if (tmp_fontWeight != map.end()) { + fromRawValue(context, tmp_fontWeight->second, result.fontWeight); + } + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } + auto tmp_marginTop = map.find("marginTop"); + if (tmp_marginTop != map.end()) { + fromRawValue(context, tmp_marginTop->second, result.marginTop); + } + auto tmp_marginBottom = map.find("marginBottom"); + if (tmp_marginBottom != map.end()) { + fromRawValue(context, tmp_marginBottom->second, result.marginBottom); + } + auto tmp_lineHeight = map.find("lineHeight"); + if (tmp_lineHeight != map.end()) { + fromRawValue(context, tmp_lineHeight->second, result.lineHeight); + } + auto tmp_textAlign = map.find("textAlign"); + if (tmp_textAlign != map.end()) { + fromRawValue(context, tmp_textAlign->second, result.textAlign); + } +} + +static inline std::string toString(const EnrichedMarkdownTextMarkdownStyleH3Struct &value) { + return "[Object EnrichedMarkdownTextMarkdownStyleH3Struct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownTextMarkdownStyleH3Struct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownTextMarkdownStyleH4Struct { + Float fontSize{0.0}; + std::string fontFamily{}; + std::string fontWeight{}; + SharedColor color{}; + Float marginTop{0.0}; + Float marginBottom{0.0}; + Float lineHeight{0.0}; + std::string textAlign{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownTextMarkdownStyleH4Struct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["fontSize"] = fontSize; + result["fontFamily"] = fontFamily; + result["fontWeight"] = fontWeight; + result["color"] = ::facebook::react::toDynamic(color); + result["marginTop"] = marginTop; + result["marginBottom"] = marginBottom; + result["lineHeight"] = lineHeight; + result["textAlign"] = textAlign; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownTextMarkdownStyleH4Struct &result) { + auto map = (std::unordered_map)value; + + auto tmp_fontSize = map.find("fontSize"); + if (tmp_fontSize != map.end()) { + fromRawValue(context, tmp_fontSize->second, result.fontSize); + } + auto tmp_fontFamily = map.find("fontFamily"); + if (tmp_fontFamily != map.end()) { + fromRawValue(context, tmp_fontFamily->second, result.fontFamily); + } + auto tmp_fontWeight = map.find("fontWeight"); + if (tmp_fontWeight != map.end()) { + fromRawValue(context, tmp_fontWeight->second, result.fontWeight); + } + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } + auto tmp_marginTop = map.find("marginTop"); + if (tmp_marginTop != map.end()) { + fromRawValue(context, tmp_marginTop->second, result.marginTop); + } + auto tmp_marginBottom = map.find("marginBottom"); + if (tmp_marginBottom != map.end()) { + fromRawValue(context, tmp_marginBottom->second, result.marginBottom); + } + auto tmp_lineHeight = map.find("lineHeight"); + if (tmp_lineHeight != map.end()) { + fromRawValue(context, tmp_lineHeight->second, result.lineHeight); + } + auto tmp_textAlign = map.find("textAlign"); + if (tmp_textAlign != map.end()) { + fromRawValue(context, tmp_textAlign->second, result.textAlign); + } +} + +static inline std::string toString(const EnrichedMarkdownTextMarkdownStyleH4Struct &value) { + return "[Object EnrichedMarkdownTextMarkdownStyleH4Struct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownTextMarkdownStyleH4Struct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownTextMarkdownStyleH5Struct { + Float fontSize{0.0}; + std::string fontFamily{}; + std::string fontWeight{}; + SharedColor color{}; + Float marginTop{0.0}; + Float marginBottom{0.0}; + Float lineHeight{0.0}; + std::string textAlign{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownTextMarkdownStyleH5Struct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["fontSize"] = fontSize; + result["fontFamily"] = fontFamily; + result["fontWeight"] = fontWeight; + result["color"] = ::facebook::react::toDynamic(color); + result["marginTop"] = marginTop; + result["marginBottom"] = marginBottom; + result["lineHeight"] = lineHeight; + result["textAlign"] = textAlign; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownTextMarkdownStyleH5Struct &result) { + auto map = (std::unordered_map)value; + + auto tmp_fontSize = map.find("fontSize"); + if (tmp_fontSize != map.end()) { + fromRawValue(context, tmp_fontSize->second, result.fontSize); + } + auto tmp_fontFamily = map.find("fontFamily"); + if (tmp_fontFamily != map.end()) { + fromRawValue(context, tmp_fontFamily->second, result.fontFamily); + } + auto tmp_fontWeight = map.find("fontWeight"); + if (tmp_fontWeight != map.end()) { + fromRawValue(context, tmp_fontWeight->second, result.fontWeight); + } + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } + auto tmp_marginTop = map.find("marginTop"); + if (tmp_marginTop != map.end()) { + fromRawValue(context, tmp_marginTop->second, result.marginTop); + } + auto tmp_marginBottom = map.find("marginBottom"); + if (tmp_marginBottom != map.end()) { + fromRawValue(context, tmp_marginBottom->second, result.marginBottom); + } + auto tmp_lineHeight = map.find("lineHeight"); + if (tmp_lineHeight != map.end()) { + fromRawValue(context, tmp_lineHeight->second, result.lineHeight); + } + auto tmp_textAlign = map.find("textAlign"); + if (tmp_textAlign != map.end()) { + fromRawValue(context, tmp_textAlign->second, result.textAlign); + } +} + +static inline std::string toString(const EnrichedMarkdownTextMarkdownStyleH5Struct &value) { + return "[Object EnrichedMarkdownTextMarkdownStyleH5Struct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownTextMarkdownStyleH5Struct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownTextMarkdownStyleH6Struct { + Float fontSize{0.0}; + std::string fontFamily{}; + std::string fontWeight{}; + SharedColor color{}; + Float marginTop{0.0}; + Float marginBottom{0.0}; + Float lineHeight{0.0}; + std::string textAlign{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownTextMarkdownStyleH6Struct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["fontSize"] = fontSize; + result["fontFamily"] = fontFamily; + result["fontWeight"] = fontWeight; + result["color"] = ::facebook::react::toDynamic(color); + result["marginTop"] = marginTop; + result["marginBottom"] = marginBottom; + result["lineHeight"] = lineHeight; + result["textAlign"] = textAlign; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownTextMarkdownStyleH6Struct &result) { + auto map = (std::unordered_map)value; + + auto tmp_fontSize = map.find("fontSize"); + if (tmp_fontSize != map.end()) { + fromRawValue(context, tmp_fontSize->second, result.fontSize); + } + auto tmp_fontFamily = map.find("fontFamily"); + if (tmp_fontFamily != map.end()) { + fromRawValue(context, tmp_fontFamily->second, result.fontFamily); + } + auto tmp_fontWeight = map.find("fontWeight"); + if (tmp_fontWeight != map.end()) { + fromRawValue(context, tmp_fontWeight->second, result.fontWeight); + } + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } + auto tmp_marginTop = map.find("marginTop"); + if (tmp_marginTop != map.end()) { + fromRawValue(context, tmp_marginTop->second, result.marginTop); + } + auto tmp_marginBottom = map.find("marginBottom"); + if (tmp_marginBottom != map.end()) { + fromRawValue(context, tmp_marginBottom->second, result.marginBottom); + } + auto tmp_lineHeight = map.find("lineHeight"); + if (tmp_lineHeight != map.end()) { + fromRawValue(context, tmp_lineHeight->second, result.lineHeight); + } + auto tmp_textAlign = map.find("textAlign"); + if (tmp_textAlign != map.end()) { + fromRawValue(context, tmp_textAlign->second, result.textAlign); + } +} + +static inline std::string toString(const EnrichedMarkdownTextMarkdownStyleH6Struct &value) { + return "[Object EnrichedMarkdownTextMarkdownStyleH6Struct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownTextMarkdownStyleH6Struct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownTextMarkdownStyleBlockquoteStruct { + Float fontSize{0.0}; + std::string fontFamily{}; + std::string fontWeight{}; + SharedColor color{}; + Float marginTop{0.0}; + Float marginBottom{0.0}; + Float lineHeight{0.0}; + SharedColor borderColor{}; + Float borderWidth{0.0}; + Float gapWidth{0.0}; + SharedColor backgroundColor{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownTextMarkdownStyleBlockquoteStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["fontSize"] = fontSize; + result["fontFamily"] = fontFamily; + result["fontWeight"] = fontWeight; + result["color"] = ::facebook::react::toDynamic(color); + result["marginTop"] = marginTop; + result["marginBottom"] = marginBottom; + result["lineHeight"] = lineHeight; + result["borderColor"] = ::facebook::react::toDynamic(borderColor); + result["borderWidth"] = borderWidth; + result["gapWidth"] = gapWidth; + result["backgroundColor"] = ::facebook::react::toDynamic(backgroundColor); + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownTextMarkdownStyleBlockquoteStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_fontSize = map.find("fontSize"); + if (tmp_fontSize != map.end()) { + fromRawValue(context, tmp_fontSize->second, result.fontSize); + } + auto tmp_fontFamily = map.find("fontFamily"); + if (tmp_fontFamily != map.end()) { + fromRawValue(context, tmp_fontFamily->second, result.fontFamily); + } + auto tmp_fontWeight = map.find("fontWeight"); + if (tmp_fontWeight != map.end()) { + fromRawValue(context, tmp_fontWeight->second, result.fontWeight); + } + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } + auto tmp_marginTop = map.find("marginTop"); + if (tmp_marginTop != map.end()) { + fromRawValue(context, tmp_marginTop->second, result.marginTop); + } + auto tmp_marginBottom = map.find("marginBottom"); + if (tmp_marginBottom != map.end()) { + fromRawValue(context, tmp_marginBottom->second, result.marginBottom); + } + auto tmp_lineHeight = map.find("lineHeight"); + if (tmp_lineHeight != map.end()) { + fromRawValue(context, tmp_lineHeight->second, result.lineHeight); + } + auto tmp_borderColor = map.find("borderColor"); + if (tmp_borderColor != map.end()) { + fromRawValue(context, tmp_borderColor->second, result.borderColor); + } + auto tmp_borderWidth = map.find("borderWidth"); + if (tmp_borderWidth != map.end()) { + fromRawValue(context, tmp_borderWidth->second, result.borderWidth); + } + auto tmp_gapWidth = map.find("gapWidth"); + if (tmp_gapWidth != map.end()) { + fromRawValue(context, tmp_gapWidth->second, result.gapWidth); + } + auto tmp_backgroundColor = map.find("backgroundColor"); + if (tmp_backgroundColor != map.end()) { + fromRawValue(context, tmp_backgroundColor->second, result.backgroundColor); + } +} + +static inline std::string toString(const EnrichedMarkdownTextMarkdownStyleBlockquoteStruct &value) { + return "[Object EnrichedMarkdownTextMarkdownStyleBlockquoteStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownTextMarkdownStyleBlockquoteStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownTextMarkdownStyleListStruct { + Float fontSize{0.0}; + std::string fontFamily{}; + std::string fontWeight{}; + SharedColor color{}; + Float marginTop{0.0}; + Float marginBottom{0.0}; + Float lineHeight{0.0}; + SharedColor bulletColor{}; + Float bulletSize{0.0}; + Float markerMinWidth{0.0}; + SharedColor markerColor{}; + std::string markerFontWeight{}; + Float gapWidth{0.0}; + Float marginLeft{0.0}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownTextMarkdownStyleListStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["fontSize"] = fontSize; + result["fontFamily"] = fontFamily; + result["fontWeight"] = fontWeight; + result["color"] = ::facebook::react::toDynamic(color); + result["marginTop"] = marginTop; + result["marginBottom"] = marginBottom; + result["lineHeight"] = lineHeight; + result["bulletColor"] = ::facebook::react::toDynamic(bulletColor); + result["bulletSize"] = bulletSize; + result["markerMinWidth"] = markerMinWidth; + result["markerColor"] = ::facebook::react::toDynamic(markerColor); + result["markerFontWeight"] = markerFontWeight; + result["gapWidth"] = gapWidth; + result["marginLeft"] = marginLeft; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownTextMarkdownStyleListStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_fontSize = map.find("fontSize"); + if (tmp_fontSize != map.end()) { + fromRawValue(context, tmp_fontSize->second, result.fontSize); + } + auto tmp_fontFamily = map.find("fontFamily"); + if (tmp_fontFamily != map.end()) { + fromRawValue(context, tmp_fontFamily->second, result.fontFamily); + } + auto tmp_fontWeight = map.find("fontWeight"); + if (tmp_fontWeight != map.end()) { + fromRawValue(context, tmp_fontWeight->second, result.fontWeight); + } + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } + auto tmp_marginTop = map.find("marginTop"); + if (tmp_marginTop != map.end()) { + fromRawValue(context, tmp_marginTop->second, result.marginTop); + } + auto tmp_marginBottom = map.find("marginBottom"); + if (tmp_marginBottom != map.end()) { + fromRawValue(context, tmp_marginBottom->second, result.marginBottom); + } + auto tmp_lineHeight = map.find("lineHeight"); + if (tmp_lineHeight != map.end()) { + fromRawValue(context, tmp_lineHeight->second, result.lineHeight); + } + auto tmp_bulletColor = map.find("bulletColor"); + if (tmp_bulletColor != map.end()) { + fromRawValue(context, tmp_bulletColor->second, result.bulletColor); + } + auto tmp_bulletSize = map.find("bulletSize"); + if (tmp_bulletSize != map.end()) { + fromRawValue(context, tmp_bulletSize->second, result.bulletSize); + } + auto tmp_markerMinWidth = map.find("markerMinWidth"); + if (tmp_markerMinWidth != map.end()) { + fromRawValue(context, tmp_markerMinWidth->second, result.markerMinWidth); + } + auto tmp_markerColor = map.find("markerColor"); + if (tmp_markerColor != map.end()) { + fromRawValue(context, tmp_markerColor->second, result.markerColor); + } + auto tmp_markerFontWeight = map.find("markerFontWeight"); + if (tmp_markerFontWeight != map.end()) { + fromRawValue(context, tmp_markerFontWeight->second, result.markerFontWeight); + } + auto tmp_gapWidth = map.find("gapWidth"); + if (tmp_gapWidth != map.end()) { + fromRawValue(context, tmp_gapWidth->second, result.gapWidth); + } + auto tmp_marginLeft = map.find("marginLeft"); + if (tmp_marginLeft != map.end()) { + fromRawValue(context, tmp_marginLeft->second, result.marginLeft); + } +} + +static inline std::string toString(const EnrichedMarkdownTextMarkdownStyleListStruct &value) { + return "[Object EnrichedMarkdownTextMarkdownStyleListStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownTextMarkdownStyleListStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownTextMarkdownStyleCodeBlockStruct { + Float fontSize{0.0}; + std::string fontFamily{}; + std::string fontWeight{}; + SharedColor color{}; + Float marginTop{0.0}; + Float marginBottom{0.0}; + Float lineHeight{0.0}; + SharedColor backgroundColor{}; + SharedColor borderColor{}; + Float borderRadius{0.0}; + Float borderWidth{0.0}; + Float padding{0.0}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownTextMarkdownStyleCodeBlockStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["fontSize"] = fontSize; + result["fontFamily"] = fontFamily; + result["fontWeight"] = fontWeight; + result["color"] = ::facebook::react::toDynamic(color); + result["marginTop"] = marginTop; + result["marginBottom"] = marginBottom; + result["lineHeight"] = lineHeight; + result["backgroundColor"] = ::facebook::react::toDynamic(backgroundColor); + result["borderColor"] = ::facebook::react::toDynamic(borderColor); + result["borderRadius"] = borderRadius; + result["borderWidth"] = borderWidth; + result["padding"] = padding; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownTextMarkdownStyleCodeBlockStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_fontSize = map.find("fontSize"); + if (tmp_fontSize != map.end()) { + fromRawValue(context, tmp_fontSize->second, result.fontSize); + } + auto tmp_fontFamily = map.find("fontFamily"); + if (tmp_fontFamily != map.end()) { + fromRawValue(context, tmp_fontFamily->second, result.fontFamily); + } + auto tmp_fontWeight = map.find("fontWeight"); + if (tmp_fontWeight != map.end()) { + fromRawValue(context, tmp_fontWeight->second, result.fontWeight); + } + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } + auto tmp_marginTop = map.find("marginTop"); + if (tmp_marginTop != map.end()) { + fromRawValue(context, tmp_marginTop->second, result.marginTop); + } + auto tmp_marginBottom = map.find("marginBottom"); + if (tmp_marginBottom != map.end()) { + fromRawValue(context, tmp_marginBottom->second, result.marginBottom); + } + auto tmp_lineHeight = map.find("lineHeight"); + if (tmp_lineHeight != map.end()) { + fromRawValue(context, tmp_lineHeight->second, result.lineHeight); + } + auto tmp_backgroundColor = map.find("backgroundColor"); + if (tmp_backgroundColor != map.end()) { + fromRawValue(context, tmp_backgroundColor->second, result.backgroundColor); + } + auto tmp_borderColor = map.find("borderColor"); + if (tmp_borderColor != map.end()) { + fromRawValue(context, tmp_borderColor->second, result.borderColor); + } + auto tmp_borderRadius = map.find("borderRadius"); + if (tmp_borderRadius != map.end()) { + fromRawValue(context, tmp_borderRadius->second, result.borderRadius); + } + auto tmp_borderWidth = map.find("borderWidth"); + if (tmp_borderWidth != map.end()) { + fromRawValue(context, tmp_borderWidth->second, result.borderWidth); + } + auto tmp_padding = map.find("padding"); + if (tmp_padding != map.end()) { + fromRawValue(context, tmp_padding->second, result.padding); + } +} + +static inline std::string toString(const EnrichedMarkdownTextMarkdownStyleCodeBlockStruct &value) { + return "[Object EnrichedMarkdownTextMarkdownStyleCodeBlockStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownTextMarkdownStyleCodeBlockStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownTextMarkdownStyleLinkStruct { + std::string fontFamily{}; + SharedColor color{}; + bool underline{false}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownTextMarkdownStyleLinkStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["fontFamily"] = fontFamily; + result["color"] = ::facebook::react::toDynamic(color); + result["underline"] = underline; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownTextMarkdownStyleLinkStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_fontFamily = map.find("fontFamily"); + if (tmp_fontFamily != map.end()) { + fromRawValue(context, tmp_fontFamily->second, result.fontFamily); + } + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } + auto tmp_underline = map.find("underline"); + if (tmp_underline != map.end()) { + fromRawValue(context, tmp_underline->second, result.underline); + } +} + +static inline std::string toString(const EnrichedMarkdownTextMarkdownStyleLinkStruct &value) { + return "[Object EnrichedMarkdownTextMarkdownStyleLinkStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownTextMarkdownStyleLinkStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownTextMarkdownStyleStrongStruct { + std::string fontFamily{}; + std::string fontWeight{}; + SharedColor color{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownTextMarkdownStyleStrongStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["fontFamily"] = fontFamily; + result["fontWeight"] = fontWeight; + result["color"] = ::facebook::react::toDynamic(color); + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownTextMarkdownStyleStrongStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_fontFamily = map.find("fontFamily"); + if (tmp_fontFamily != map.end()) { + fromRawValue(context, tmp_fontFamily->second, result.fontFamily); + } + auto tmp_fontWeight = map.find("fontWeight"); + if (tmp_fontWeight != map.end()) { + fromRawValue(context, tmp_fontWeight->second, result.fontWeight); + } + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } +} + +static inline std::string toString(const EnrichedMarkdownTextMarkdownStyleStrongStruct &value) { + return "[Object EnrichedMarkdownTextMarkdownStyleStrongStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownTextMarkdownStyleStrongStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownTextMarkdownStyleEmStruct { + std::string fontFamily{}; + std::string fontStyle{}; + SharedColor color{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownTextMarkdownStyleEmStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["fontFamily"] = fontFamily; + result["fontStyle"] = fontStyle; + result["color"] = ::facebook::react::toDynamic(color); + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownTextMarkdownStyleEmStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_fontFamily = map.find("fontFamily"); + if (tmp_fontFamily != map.end()) { + fromRawValue(context, tmp_fontFamily->second, result.fontFamily); + } + auto tmp_fontStyle = map.find("fontStyle"); + if (tmp_fontStyle != map.end()) { + fromRawValue(context, tmp_fontStyle->second, result.fontStyle); + } + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } +} + +static inline std::string toString(const EnrichedMarkdownTextMarkdownStyleEmStruct &value) { + return "[Object EnrichedMarkdownTextMarkdownStyleEmStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownTextMarkdownStyleEmStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownTextMarkdownStyleStrikethroughStruct { + SharedColor color{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownTextMarkdownStyleStrikethroughStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["color"] = ::facebook::react::toDynamic(color); + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownTextMarkdownStyleStrikethroughStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } +} + +static inline std::string toString(const EnrichedMarkdownTextMarkdownStyleStrikethroughStruct &value) { + return "[Object EnrichedMarkdownTextMarkdownStyleStrikethroughStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownTextMarkdownStyleStrikethroughStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownTextMarkdownStyleUnderlineStruct { + SharedColor color{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownTextMarkdownStyleUnderlineStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["color"] = ::facebook::react::toDynamic(color); + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownTextMarkdownStyleUnderlineStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } +} + +static inline std::string toString(const EnrichedMarkdownTextMarkdownStyleUnderlineStruct &value) { + return "[Object EnrichedMarkdownTextMarkdownStyleUnderlineStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownTextMarkdownStyleUnderlineStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownTextMarkdownStyleCodeStruct { + std::string fontFamily{}; + Float fontSize{0.0}; + SharedColor color{}; + SharedColor backgroundColor{}; + SharedColor borderColor{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownTextMarkdownStyleCodeStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["fontFamily"] = fontFamily; + result["fontSize"] = fontSize; + result["color"] = ::facebook::react::toDynamic(color); + result["backgroundColor"] = ::facebook::react::toDynamic(backgroundColor); + result["borderColor"] = ::facebook::react::toDynamic(borderColor); + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownTextMarkdownStyleCodeStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_fontFamily = map.find("fontFamily"); + if (tmp_fontFamily != map.end()) { + fromRawValue(context, tmp_fontFamily->second, result.fontFamily); + } + auto tmp_fontSize = map.find("fontSize"); + if (tmp_fontSize != map.end()) { + fromRawValue(context, tmp_fontSize->second, result.fontSize); + } + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } + auto tmp_backgroundColor = map.find("backgroundColor"); + if (tmp_backgroundColor != map.end()) { + fromRawValue(context, tmp_backgroundColor->second, result.backgroundColor); + } + auto tmp_borderColor = map.find("borderColor"); + if (tmp_borderColor != map.end()) { + fromRawValue(context, tmp_borderColor->second, result.borderColor); + } +} + +static inline std::string toString(const EnrichedMarkdownTextMarkdownStyleCodeStruct &value) { + return "[Object EnrichedMarkdownTextMarkdownStyleCodeStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownTextMarkdownStyleCodeStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownTextMarkdownStyleImageStruct { + Float height{0.0}; + Float borderRadius{0.0}; + Float marginTop{0.0}; + Float marginBottom{0.0}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownTextMarkdownStyleImageStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["height"] = height; + result["borderRadius"] = borderRadius; + result["marginTop"] = marginTop; + result["marginBottom"] = marginBottom; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownTextMarkdownStyleImageStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_height = map.find("height"); + if (tmp_height != map.end()) { + fromRawValue(context, tmp_height->second, result.height); + } + auto tmp_borderRadius = map.find("borderRadius"); + if (tmp_borderRadius != map.end()) { + fromRawValue(context, tmp_borderRadius->second, result.borderRadius); + } + auto tmp_marginTop = map.find("marginTop"); + if (tmp_marginTop != map.end()) { + fromRawValue(context, tmp_marginTop->second, result.marginTop); + } + auto tmp_marginBottom = map.find("marginBottom"); + if (tmp_marginBottom != map.end()) { + fromRawValue(context, tmp_marginBottom->second, result.marginBottom); + } +} + +static inline std::string toString(const EnrichedMarkdownTextMarkdownStyleImageStruct &value) { + return "[Object EnrichedMarkdownTextMarkdownStyleImageStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownTextMarkdownStyleImageStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownTextMarkdownStyleInlineImageStruct { + Float size{0.0}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownTextMarkdownStyleInlineImageStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["size"] = size; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownTextMarkdownStyleInlineImageStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_size = map.find("size"); + if (tmp_size != map.end()) { + fromRawValue(context, tmp_size->second, result.size); + } +} + +static inline std::string toString(const EnrichedMarkdownTextMarkdownStyleInlineImageStruct &value) { + return "[Object EnrichedMarkdownTextMarkdownStyleInlineImageStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownTextMarkdownStyleInlineImageStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownTextMarkdownStyleThematicBreakStruct { + SharedColor color{}; + Float height{0.0}; + Float marginTop{0.0}; + Float marginBottom{0.0}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownTextMarkdownStyleThematicBreakStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["color"] = ::facebook::react::toDynamic(color); + result["height"] = height; + result["marginTop"] = marginTop; + result["marginBottom"] = marginBottom; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownTextMarkdownStyleThematicBreakStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } + auto tmp_height = map.find("height"); + if (tmp_height != map.end()) { + fromRawValue(context, tmp_height->second, result.height); + } + auto tmp_marginTop = map.find("marginTop"); + if (tmp_marginTop != map.end()) { + fromRawValue(context, tmp_marginTop->second, result.marginTop); + } + auto tmp_marginBottom = map.find("marginBottom"); + if (tmp_marginBottom != map.end()) { + fromRawValue(context, tmp_marginBottom->second, result.marginBottom); + } +} + +static inline std::string toString(const EnrichedMarkdownTextMarkdownStyleThematicBreakStruct &value) { + return "[Object EnrichedMarkdownTextMarkdownStyleThematicBreakStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownTextMarkdownStyleThematicBreakStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownTextMarkdownStyleTableStruct { + Float fontSize{0.0}; + std::string fontFamily{}; + std::string fontWeight{}; + SharedColor color{}; + Float marginTop{0.0}; + Float marginBottom{0.0}; + Float lineHeight{0.0}; + std::string headerFontFamily{}; + SharedColor headerBackgroundColor{}; + SharedColor headerTextColor{}; + SharedColor rowEvenBackgroundColor{}; + SharedColor rowOddBackgroundColor{}; + SharedColor borderColor{}; + Float borderWidth{0.0}; + Float borderRadius{0.0}; + Float cellPaddingHorizontal{0.0}; + Float cellPaddingVertical{0.0}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownTextMarkdownStyleTableStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["fontSize"] = fontSize; + result["fontFamily"] = fontFamily; + result["fontWeight"] = fontWeight; + result["color"] = ::facebook::react::toDynamic(color); + result["marginTop"] = marginTop; + result["marginBottom"] = marginBottom; + result["lineHeight"] = lineHeight; + result["headerFontFamily"] = headerFontFamily; + result["headerBackgroundColor"] = ::facebook::react::toDynamic(headerBackgroundColor); + result["headerTextColor"] = ::facebook::react::toDynamic(headerTextColor); + result["rowEvenBackgroundColor"] = ::facebook::react::toDynamic(rowEvenBackgroundColor); + result["rowOddBackgroundColor"] = ::facebook::react::toDynamic(rowOddBackgroundColor); + result["borderColor"] = ::facebook::react::toDynamic(borderColor); + result["borderWidth"] = borderWidth; + result["borderRadius"] = borderRadius; + result["cellPaddingHorizontal"] = cellPaddingHorizontal; + result["cellPaddingVertical"] = cellPaddingVertical; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownTextMarkdownStyleTableStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_fontSize = map.find("fontSize"); + if (tmp_fontSize != map.end()) { + fromRawValue(context, tmp_fontSize->second, result.fontSize); + } + auto tmp_fontFamily = map.find("fontFamily"); + if (tmp_fontFamily != map.end()) { + fromRawValue(context, tmp_fontFamily->second, result.fontFamily); + } + auto tmp_fontWeight = map.find("fontWeight"); + if (tmp_fontWeight != map.end()) { + fromRawValue(context, tmp_fontWeight->second, result.fontWeight); + } + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } + auto tmp_marginTop = map.find("marginTop"); + if (tmp_marginTop != map.end()) { + fromRawValue(context, tmp_marginTop->second, result.marginTop); + } + auto tmp_marginBottom = map.find("marginBottom"); + if (tmp_marginBottom != map.end()) { + fromRawValue(context, tmp_marginBottom->second, result.marginBottom); + } + auto tmp_lineHeight = map.find("lineHeight"); + if (tmp_lineHeight != map.end()) { + fromRawValue(context, tmp_lineHeight->second, result.lineHeight); + } + auto tmp_headerFontFamily = map.find("headerFontFamily"); + if (tmp_headerFontFamily != map.end()) { + fromRawValue(context, tmp_headerFontFamily->second, result.headerFontFamily); + } + auto tmp_headerBackgroundColor = map.find("headerBackgroundColor"); + if (tmp_headerBackgroundColor != map.end()) { + fromRawValue(context, tmp_headerBackgroundColor->second, result.headerBackgroundColor); + } + auto tmp_headerTextColor = map.find("headerTextColor"); + if (tmp_headerTextColor != map.end()) { + fromRawValue(context, tmp_headerTextColor->second, result.headerTextColor); + } + auto tmp_rowEvenBackgroundColor = map.find("rowEvenBackgroundColor"); + if (tmp_rowEvenBackgroundColor != map.end()) { + fromRawValue(context, tmp_rowEvenBackgroundColor->second, result.rowEvenBackgroundColor); + } + auto tmp_rowOddBackgroundColor = map.find("rowOddBackgroundColor"); + if (tmp_rowOddBackgroundColor != map.end()) { + fromRawValue(context, tmp_rowOddBackgroundColor->second, result.rowOddBackgroundColor); + } + auto tmp_borderColor = map.find("borderColor"); + if (tmp_borderColor != map.end()) { + fromRawValue(context, tmp_borderColor->second, result.borderColor); + } + auto tmp_borderWidth = map.find("borderWidth"); + if (tmp_borderWidth != map.end()) { + fromRawValue(context, tmp_borderWidth->second, result.borderWidth); + } + auto tmp_borderRadius = map.find("borderRadius"); + if (tmp_borderRadius != map.end()) { + fromRawValue(context, tmp_borderRadius->second, result.borderRadius); + } + auto tmp_cellPaddingHorizontal = map.find("cellPaddingHorizontal"); + if (tmp_cellPaddingHorizontal != map.end()) { + fromRawValue(context, tmp_cellPaddingHorizontal->second, result.cellPaddingHorizontal); + } + auto tmp_cellPaddingVertical = map.find("cellPaddingVertical"); + if (tmp_cellPaddingVertical != map.end()) { + fromRawValue(context, tmp_cellPaddingVertical->second, result.cellPaddingVertical); + } +} + +static inline std::string toString(const EnrichedMarkdownTextMarkdownStyleTableStruct &value) { + return "[Object EnrichedMarkdownTextMarkdownStyleTableStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownTextMarkdownStyleTableStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownTextMarkdownStyleTaskListStruct { + SharedColor checkedColor{}; + SharedColor borderColor{}; + Float checkboxSize{0.0}; + Float checkboxBorderRadius{0.0}; + SharedColor checkmarkColor{}; + SharedColor checkedTextColor{}; + bool checkedStrikethrough{false}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownTextMarkdownStyleTaskListStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["checkedColor"] = ::facebook::react::toDynamic(checkedColor); + result["borderColor"] = ::facebook::react::toDynamic(borderColor); + result["checkboxSize"] = checkboxSize; + result["checkboxBorderRadius"] = checkboxBorderRadius; + result["checkmarkColor"] = ::facebook::react::toDynamic(checkmarkColor); + result["checkedTextColor"] = ::facebook::react::toDynamic(checkedTextColor); + result["checkedStrikethrough"] = checkedStrikethrough; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownTextMarkdownStyleTaskListStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_checkedColor = map.find("checkedColor"); + if (tmp_checkedColor != map.end()) { + fromRawValue(context, tmp_checkedColor->second, result.checkedColor); + } + auto tmp_borderColor = map.find("borderColor"); + if (tmp_borderColor != map.end()) { + fromRawValue(context, tmp_borderColor->second, result.borderColor); + } + auto tmp_checkboxSize = map.find("checkboxSize"); + if (tmp_checkboxSize != map.end()) { + fromRawValue(context, tmp_checkboxSize->second, result.checkboxSize); + } + auto tmp_checkboxBorderRadius = map.find("checkboxBorderRadius"); + if (tmp_checkboxBorderRadius != map.end()) { + fromRawValue(context, tmp_checkboxBorderRadius->second, result.checkboxBorderRadius); + } + auto tmp_checkmarkColor = map.find("checkmarkColor"); + if (tmp_checkmarkColor != map.end()) { + fromRawValue(context, tmp_checkmarkColor->second, result.checkmarkColor); + } + auto tmp_checkedTextColor = map.find("checkedTextColor"); + if (tmp_checkedTextColor != map.end()) { + fromRawValue(context, tmp_checkedTextColor->second, result.checkedTextColor); + } + auto tmp_checkedStrikethrough = map.find("checkedStrikethrough"); + if (tmp_checkedStrikethrough != map.end()) { + fromRawValue(context, tmp_checkedStrikethrough->second, result.checkedStrikethrough); + } +} + +static inline std::string toString(const EnrichedMarkdownTextMarkdownStyleTaskListStruct &value) { + return "[Object EnrichedMarkdownTextMarkdownStyleTaskListStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownTextMarkdownStyleTaskListStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownTextMarkdownStyleMathStruct { + Float fontSize{0.0}; + SharedColor color{}; + SharedColor backgroundColor{}; + Float padding{0.0}; + Float marginTop{0.0}; + Float marginBottom{0.0}; + std::string textAlign{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownTextMarkdownStyleMathStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["fontSize"] = fontSize; + result["color"] = ::facebook::react::toDynamic(color); + result["backgroundColor"] = ::facebook::react::toDynamic(backgroundColor); + result["padding"] = padding; + result["marginTop"] = marginTop; + result["marginBottom"] = marginBottom; + result["textAlign"] = textAlign; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownTextMarkdownStyleMathStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_fontSize = map.find("fontSize"); + if (tmp_fontSize != map.end()) { + fromRawValue(context, tmp_fontSize->second, result.fontSize); + } + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } + auto tmp_backgroundColor = map.find("backgroundColor"); + if (tmp_backgroundColor != map.end()) { + fromRawValue(context, tmp_backgroundColor->second, result.backgroundColor); + } + auto tmp_padding = map.find("padding"); + if (tmp_padding != map.end()) { + fromRawValue(context, tmp_padding->second, result.padding); + } + auto tmp_marginTop = map.find("marginTop"); + if (tmp_marginTop != map.end()) { + fromRawValue(context, tmp_marginTop->second, result.marginTop); + } + auto tmp_marginBottom = map.find("marginBottom"); + if (tmp_marginBottom != map.end()) { + fromRawValue(context, tmp_marginBottom->second, result.marginBottom); + } + auto tmp_textAlign = map.find("textAlign"); + if (tmp_textAlign != map.end()) { + fromRawValue(context, tmp_textAlign->second, result.textAlign); + } +} + +static inline std::string toString(const EnrichedMarkdownTextMarkdownStyleMathStruct &value) { + return "[Object EnrichedMarkdownTextMarkdownStyleMathStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownTextMarkdownStyleMathStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownTextMarkdownStyleInlineMathStruct { + SharedColor color{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownTextMarkdownStyleInlineMathStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["color"] = ::facebook::react::toDynamic(color); + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownTextMarkdownStyleInlineMathStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } +} + +static inline std::string toString(const EnrichedMarkdownTextMarkdownStyleInlineMathStruct &value) { + return "[Object EnrichedMarkdownTextMarkdownStyleInlineMathStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownTextMarkdownStyleInlineMathStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownTextMarkdownStyleSpoilerParticlesStruct { + Float density{0.0}; + Float speed{0.0}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownTextMarkdownStyleSpoilerParticlesStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["density"] = density; + result["speed"] = speed; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownTextMarkdownStyleSpoilerParticlesStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_density = map.find("density"); + if (tmp_density != map.end()) { + fromRawValue(context, tmp_density->second, result.density); + } + auto tmp_speed = map.find("speed"); + if (tmp_speed != map.end()) { + fromRawValue(context, tmp_speed->second, result.speed); + } +} + +static inline std::string toString(const EnrichedMarkdownTextMarkdownStyleSpoilerParticlesStruct &value) { + return "[Object EnrichedMarkdownTextMarkdownStyleSpoilerParticlesStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownTextMarkdownStyleSpoilerParticlesStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownTextMarkdownStyleSpoilerSolidStruct { + Float borderRadius{0.0}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownTextMarkdownStyleSpoilerSolidStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["borderRadius"] = borderRadius; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownTextMarkdownStyleSpoilerSolidStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_borderRadius = map.find("borderRadius"); + if (tmp_borderRadius != map.end()) { + fromRawValue(context, tmp_borderRadius->second, result.borderRadius); + } +} + +static inline std::string toString(const EnrichedMarkdownTextMarkdownStyleSpoilerSolidStruct &value) { + return "[Object EnrichedMarkdownTextMarkdownStyleSpoilerSolidStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownTextMarkdownStyleSpoilerSolidStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownTextMarkdownStyleSpoilerStruct { + SharedColor color{}; + EnrichedMarkdownTextMarkdownStyleSpoilerParticlesStruct particles{}; + EnrichedMarkdownTextMarkdownStyleSpoilerSolidStruct solid{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownTextMarkdownStyleSpoilerStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["color"] = ::facebook::react::toDynamic(color); + result["particles"] = ::facebook::react::toDynamic(particles); + result["solid"] = ::facebook::react::toDynamic(solid); + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownTextMarkdownStyleSpoilerStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } + auto tmp_particles = map.find("particles"); + if (tmp_particles != map.end()) { + fromRawValue(context, tmp_particles->second, result.particles); + } + auto tmp_solid = map.find("solid"); + if (tmp_solid != map.end()) { + fromRawValue(context, tmp_solid->second, result.solid); + } +} + +static inline std::string toString(const EnrichedMarkdownTextMarkdownStyleSpoilerStruct &value) { + return "[Object EnrichedMarkdownTextMarkdownStyleSpoilerStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownTextMarkdownStyleSpoilerStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownTextMarkdownStyleMentionStruct { + SharedColor color{}; + SharedColor backgroundColor{}; + SharedColor borderColor{}; + Float borderWidth{0.0}; + Float borderRadius{0.0}; + Float paddingHorizontal{0.0}; + Float paddingVertical{0.0}; + std::string fontFamily{}; + std::string fontWeight{}; + Float fontSize{0.0}; + Float pressedOpacity{0.0}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownTextMarkdownStyleMentionStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["color"] = ::facebook::react::toDynamic(color); + result["backgroundColor"] = ::facebook::react::toDynamic(backgroundColor); + result["borderColor"] = ::facebook::react::toDynamic(borderColor); + result["borderWidth"] = borderWidth; + result["borderRadius"] = borderRadius; + result["paddingHorizontal"] = paddingHorizontal; + result["paddingVertical"] = paddingVertical; + result["fontFamily"] = fontFamily; + result["fontWeight"] = fontWeight; + result["fontSize"] = fontSize; + result["pressedOpacity"] = pressedOpacity; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownTextMarkdownStyleMentionStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } + auto tmp_backgroundColor = map.find("backgroundColor"); + if (tmp_backgroundColor != map.end()) { + fromRawValue(context, tmp_backgroundColor->second, result.backgroundColor); + } + auto tmp_borderColor = map.find("borderColor"); + if (tmp_borderColor != map.end()) { + fromRawValue(context, tmp_borderColor->second, result.borderColor); + } + auto tmp_borderWidth = map.find("borderWidth"); + if (tmp_borderWidth != map.end()) { + fromRawValue(context, tmp_borderWidth->second, result.borderWidth); + } + auto tmp_borderRadius = map.find("borderRadius"); + if (tmp_borderRadius != map.end()) { + fromRawValue(context, tmp_borderRadius->second, result.borderRadius); + } + auto tmp_paddingHorizontal = map.find("paddingHorizontal"); + if (tmp_paddingHorizontal != map.end()) { + fromRawValue(context, tmp_paddingHorizontal->second, result.paddingHorizontal); + } + auto tmp_paddingVertical = map.find("paddingVertical"); + if (tmp_paddingVertical != map.end()) { + fromRawValue(context, tmp_paddingVertical->second, result.paddingVertical); + } + auto tmp_fontFamily = map.find("fontFamily"); + if (tmp_fontFamily != map.end()) { + fromRawValue(context, tmp_fontFamily->second, result.fontFamily); + } + auto tmp_fontWeight = map.find("fontWeight"); + if (tmp_fontWeight != map.end()) { + fromRawValue(context, tmp_fontWeight->second, result.fontWeight); + } + auto tmp_fontSize = map.find("fontSize"); + if (tmp_fontSize != map.end()) { + fromRawValue(context, tmp_fontSize->second, result.fontSize); + } + auto tmp_pressedOpacity = map.find("pressedOpacity"); + if (tmp_pressedOpacity != map.end()) { + fromRawValue(context, tmp_pressedOpacity->second, result.pressedOpacity); + } +} + +static inline std::string toString(const EnrichedMarkdownTextMarkdownStyleMentionStruct &value) { + return "[Object EnrichedMarkdownTextMarkdownStyleMentionStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownTextMarkdownStyleMentionStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownTextMarkdownStyleCitationStruct { + SharedColor color{}; + Float fontSizeMultiplier{0.0}; + Float baselineOffsetPx{0.0}; + std::string fontWeight{}; + bool underline{false}; + SharedColor backgroundColor{}; + Float paddingHorizontal{0.0}; + Float paddingVertical{0.0}; + SharedColor borderColor{}; + Float borderWidth{0.0}; + Float borderRadius{0.0}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownTextMarkdownStyleCitationStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["color"] = ::facebook::react::toDynamic(color); + result["fontSizeMultiplier"] = fontSizeMultiplier; + result["baselineOffsetPx"] = baselineOffsetPx; + result["fontWeight"] = fontWeight; + result["underline"] = underline; + result["backgroundColor"] = ::facebook::react::toDynamic(backgroundColor); + result["paddingHorizontal"] = paddingHorizontal; + result["paddingVertical"] = paddingVertical; + result["borderColor"] = ::facebook::react::toDynamic(borderColor); + result["borderWidth"] = borderWidth; + result["borderRadius"] = borderRadius; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownTextMarkdownStyleCitationStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_color = map.find("color"); + if (tmp_color != map.end()) { + fromRawValue(context, tmp_color->second, result.color); + } + auto tmp_fontSizeMultiplier = map.find("fontSizeMultiplier"); + if (tmp_fontSizeMultiplier != map.end()) { + fromRawValue(context, tmp_fontSizeMultiplier->second, result.fontSizeMultiplier); + } + auto tmp_baselineOffsetPx = map.find("baselineOffsetPx"); + if (tmp_baselineOffsetPx != map.end()) { + fromRawValue(context, tmp_baselineOffsetPx->second, result.baselineOffsetPx); + } + auto tmp_fontWeight = map.find("fontWeight"); + if (tmp_fontWeight != map.end()) { + fromRawValue(context, tmp_fontWeight->second, result.fontWeight); + } + auto tmp_underline = map.find("underline"); + if (tmp_underline != map.end()) { + fromRawValue(context, tmp_underline->second, result.underline); + } + auto tmp_backgroundColor = map.find("backgroundColor"); + if (tmp_backgroundColor != map.end()) { + fromRawValue(context, tmp_backgroundColor->second, result.backgroundColor); + } + auto tmp_paddingHorizontal = map.find("paddingHorizontal"); + if (tmp_paddingHorizontal != map.end()) { + fromRawValue(context, tmp_paddingHorizontal->second, result.paddingHorizontal); + } + auto tmp_paddingVertical = map.find("paddingVertical"); + if (tmp_paddingVertical != map.end()) { + fromRawValue(context, tmp_paddingVertical->second, result.paddingVertical); + } + auto tmp_borderColor = map.find("borderColor"); + if (tmp_borderColor != map.end()) { + fromRawValue(context, tmp_borderColor->second, result.borderColor); + } + auto tmp_borderWidth = map.find("borderWidth"); + if (tmp_borderWidth != map.end()) { + fromRawValue(context, tmp_borderWidth->second, result.borderWidth); + } + auto tmp_borderRadius = map.find("borderRadius"); + if (tmp_borderRadius != map.end()) { + fromRawValue(context, tmp_borderRadius->second, result.borderRadius); + } +} + +static inline std::string toString(const EnrichedMarkdownTextMarkdownStyleCitationStruct &value) { + return "[Object EnrichedMarkdownTextMarkdownStyleCitationStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownTextMarkdownStyleCitationStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownTextMarkdownStyleStruct { + EnrichedMarkdownTextMarkdownStyleParagraphStruct paragraph{}; + EnrichedMarkdownTextMarkdownStyleH1Struct h1{}; + EnrichedMarkdownTextMarkdownStyleH2Struct h2{}; + EnrichedMarkdownTextMarkdownStyleH3Struct h3{}; + EnrichedMarkdownTextMarkdownStyleH4Struct h4{}; + EnrichedMarkdownTextMarkdownStyleH5Struct h5{}; + EnrichedMarkdownTextMarkdownStyleH6Struct h6{}; + EnrichedMarkdownTextMarkdownStyleBlockquoteStruct blockquote{}; + EnrichedMarkdownTextMarkdownStyleListStruct list{}; + EnrichedMarkdownTextMarkdownStyleCodeBlockStruct codeBlock{}; + EnrichedMarkdownTextMarkdownStyleLinkStruct link{}; + EnrichedMarkdownTextMarkdownStyleStrongStruct strong{}; + EnrichedMarkdownTextMarkdownStyleEmStruct em{}; + EnrichedMarkdownTextMarkdownStyleStrikethroughStruct strikethrough{}; + EnrichedMarkdownTextMarkdownStyleUnderlineStruct underline{}; + EnrichedMarkdownTextMarkdownStyleCodeStruct code{}; + EnrichedMarkdownTextMarkdownStyleImageStruct image{}; + EnrichedMarkdownTextMarkdownStyleInlineImageStruct inlineImage{}; + EnrichedMarkdownTextMarkdownStyleThematicBreakStruct thematicBreak{}; + EnrichedMarkdownTextMarkdownStyleTableStruct table{}; + EnrichedMarkdownTextMarkdownStyleTaskListStruct taskList{}; + EnrichedMarkdownTextMarkdownStyleMathStruct math{}; + EnrichedMarkdownTextMarkdownStyleInlineMathStruct inlineMath{}; + EnrichedMarkdownTextMarkdownStyleSpoilerStruct spoiler{}; + EnrichedMarkdownTextMarkdownStyleMentionStruct mention{}; + EnrichedMarkdownTextMarkdownStyleCitationStruct citation{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownTextMarkdownStyleStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["paragraph"] = ::facebook::react::toDynamic(paragraph); + result["h1"] = ::facebook::react::toDynamic(h1); + result["h2"] = ::facebook::react::toDynamic(h2); + result["h3"] = ::facebook::react::toDynamic(h3); + result["h4"] = ::facebook::react::toDynamic(h4); + result["h5"] = ::facebook::react::toDynamic(h5); + result["h6"] = ::facebook::react::toDynamic(h6); + result["blockquote"] = ::facebook::react::toDynamic(blockquote); + result["list"] = ::facebook::react::toDynamic(list); + result["codeBlock"] = ::facebook::react::toDynamic(codeBlock); + result["link"] = ::facebook::react::toDynamic(link); + result["strong"] = ::facebook::react::toDynamic(strong); + result["em"] = ::facebook::react::toDynamic(em); + result["strikethrough"] = ::facebook::react::toDynamic(strikethrough); + result["underline"] = ::facebook::react::toDynamic(underline); + result["code"] = ::facebook::react::toDynamic(code); + result["image"] = ::facebook::react::toDynamic(image); + result["inlineImage"] = ::facebook::react::toDynamic(inlineImage); + result["thematicBreak"] = ::facebook::react::toDynamic(thematicBreak); + result["table"] = ::facebook::react::toDynamic(table); + result["taskList"] = ::facebook::react::toDynamic(taskList); + result["math"] = ::facebook::react::toDynamic(math); + result["inlineMath"] = ::facebook::react::toDynamic(inlineMath); + result["spoiler"] = ::facebook::react::toDynamic(spoiler); + result["mention"] = ::facebook::react::toDynamic(mention); + result["citation"] = ::facebook::react::toDynamic(citation); + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownTextMarkdownStyleStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_paragraph = map.find("paragraph"); + if (tmp_paragraph != map.end()) { + fromRawValue(context, tmp_paragraph->second, result.paragraph); + } + auto tmp_h1 = map.find("h1"); + if (tmp_h1 != map.end()) { + fromRawValue(context, tmp_h1->second, result.h1); + } + auto tmp_h2 = map.find("h2"); + if (tmp_h2 != map.end()) { + fromRawValue(context, tmp_h2->second, result.h2); + } + auto tmp_h3 = map.find("h3"); + if (tmp_h3 != map.end()) { + fromRawValue(context, tmp_h3->second, result.h3); + } + auto tmp_h4 = map.find("h4"); + if (tmp_h4 != map.end()) { + fromRawValue(context, tmp_h4->second, result.h4); + } + auto tmp_h5 = map.find("h5"); + if (tmp_h5 != map.end()) { + fromRawValue(context, tmp_h5->second, result.h5); + } + auto tmp_h6 = map.find("h6"); + if (tmp_h6 != map.end()) { + fromRawValue(context, tmp_h6->second, result.h6); + } + auto tmp_blockquote = map.find("blockquote"); + if (tmp_blockquote != map.end()) { + fromRawValue(context, tmp_blockquote->second, result.blockquote); + } + auto tmp_list = map.find("list"); + if (tmp_list != map.end()) { + fromRawValue(context, tmp_list->second, result.list); + } + auto tmp_codeBlock = map.find("codeBlock"); + if (tmp_codeBlock != map.end()) { + fromRawValue(context, tmp_codeBlock->second, result.codeBlock); + } + auto tmp_link = map.find("link"); + if (tmp_link != map.end()) { + fromRawValue(context, tmp_link->second, result.link); + } + auto tmp_strong = map.find("strong"); + if (tmp_strong != map.end()) { + fromRawValue(context, tmp_strong->second, result.strong); + } + auto tmp_em = map.find("em"); + if (tmp_em != map.end()) { + fromRawValue(context, tmp_em->second, result.em); + } + auto tmp_strikethrough = map.find("strikethrough"); + if (tmp_strikethrough != map.end()) { + fromRawValue(context, tmp_strikethrough->second, result.strikethrough); + } + auto tmp_underline = map.find("underline"); + if (tmp_underline != map.end()) { + fromRawValue(context, tmp_underline->second, result.underline); + } + auto tmp_code = map.find("code"); + if (tmp_code != map.end()) { + fromRawValue(context, tmp_code->second, result.code); + } + auto tmp_image = map.find("image"); + if (tmp_image != map.end()) { + fromRawValue(context, tmp_image->second, result.image); + } + auto tmp_inlineImage = map.find("inlineImage"); + if (tmp_inlineImage != map.end()) { + fromRawValue(context, tmp_inlineImage->second, result.inlineImage); + } + auto tmp_thematicBreak = map.find("thematicBreak"); + if (tmp_thematicBreak != map.end()) { + fromRawValue(context, tmp_thematicBreak->second, result.thematicBreak); + } + auto tmp_table = map.find("table"); + if (tmp_table != map.end()) { + fromRawValue(context, tmp_table->second, result.table); + } + auto tmp_taskList = map.find("taskList"); + if (tmp_taskList != map.end()) { + fromRawValue(context, tmp_taskList->second, result.taskList); + } + auto tmp_math = map.find("math"); + if (tmp_math != map.end()) { + fromRawValue(context, tmp_math->second, result.math); + } + auto tmp_inlineMath = map.find("inlineMath"); + if (tmp_inlineMath != map.end()) { + fromRawValue(context, tmp_inlineMath->second, result.inlineMath); + } + auto tmp_spoiler = map.find("spoiler"); + if (tmp_spoiler != map.end()) { + fromRawValue(context, tmp_spoiler->second, result.spoiler); + } + auto tmp_mention = map.find("mention"); + if (tmp_mention != map.end()) { + fromRawValue(context, tmp_mention->second, result.mention); + } + auto tmp_citation = map.find("citation"); + if (tmp_citation != map.end()) { + fromRawValue(context, tmp_citation->second, result.citation); + } +} + +static inline std::string toString(const EnrichedMarkdownTextMarkdownStyleStruct &value) { + return "[Object EnrichedMarkdownTextMarkdownStyleStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownTextMarkdownStyleStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownTextMd4cFlagsStruct { + bool underline{false}; + bool latexMath{false}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownTextMd4cFlagsStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["underline"] = underline; + result["latexMath"] = latexMath; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownTextMd4cFlagsStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_underline = map.find("underline"); + if (tmp_underline != map.end()) { + fromRawValue(context, tmp_underline->second, result.underline); + } + auto tmp_latexMath = map.find("latexMath"); + if (tmp_latexMath != map.end()) { + fromRawValue(context, tmp_latexMath->second, result.latexMath); + } +} + +static inline std::string toString(const EnrichedMarkdownTextMd4cFlagsStruct &value) { + return "[Object EnrichedMarkdownTextMd4cFlagsStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownTextMd4cFlagsStruct &value) { + return value.toDynamic(); +} +#endif + +struct EnrichedMarkdownTextContextMenuItemsStruct { + std::string text{}; + std::string icon{}; + + +#ifdef RN_SERIALIZABLE_STATE + bool operator==(const EnrichedMarkdownTextContextMenuItemsStruct&) const = default; + + folly::dynamic toDynamic() const { + folly::dynamic result = folly::dynamic::object(); + result["text"] = text; + result["icon"] = icon; + return result; + } +#endif +}; + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedMarkdownTextContextMenuItemsStruct &result) { + auto map = (std::unordered_map)value; + + auto tmp_text = map.find("text"); + if (tmp_text != map.end()) { + fromRawValue(context, tmp_text->second, result.text); + } + auto tmp_icon = map.find("icon"); + if (tmp_icon != map.end()) { + fromRawValue(context, tmp_icon->second, result.icon); + } +} + +static inline std::string toString(const EnrichedMarkdownTextContextMenuItemsStruct &value) { + return "[Object EnrichedMarkdownTextContextMenuItemsStruct]"; +} + +#ifdef RN_SERIALIZABLE_STATE +static inline folly::dynamic toDynamic(const EnrichedMarkdownTextContextMenuItemsStruct &value) { + return value.toDynamic(); +} +#endif + +static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, std::vector &result) { + auto items = (std::vector)value; + for (const auto &item : items) { + EnrichedMarkdownTextContextMenuItemsStruct newItem; + fromRawValue(context, item, newItem); + result.emplace_back(newItem); + } +} + +class EnrichedMarkdownTextProps final : public ViewProps { + public: + EnrichedMarkdownTextProps() = default; + EnrichedMarkdownTextProps(const PropsParserContext& context, const EnrichedMarkdownTextProps &sourceProps, const RawProps &rawProps); + +#pragma mark - Props + + std::string markdown{}; + EnrichedMarkdownTextMarkdownStyleStruct markdownStyle{}; + bool enableLinkPreview{true}; + bool selectable{false}; + SharedColor selectionColor{}; + SharedColor selectionHandleColor{}; + EnrichedMarkdownTextMd4cFlagsStruct md4cFlags{}; + bool allowFontScaling{true}; + Float maxFontSizeMultiplier{0.0}; + bool allowTrailingMargin{false}; + bool streamingAnimation{false}; + std::string spoilerOverlay{std::string{"particles"}}; + std::vector contextMenuItems{}; + + #ifdef RN_SERIALIZABLE_STATE + ComponentName getDiffPropsImplementationTarget() const override; + + folly::dynamic getDiffProps(const Props* prevProps) const override; + #endif + + +}; + +} // namespace facebook::react diff --git a/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/RCTComponentViewHelpers.h b/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/RCTComponentViewHelpers.h new file mode 100644 index 00000000..016b9fb4 --- /dev/null +++ b/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/RCTComponentViewHelpers.h @@ -0,0 +1,299 @@ +/** +* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). +* +* Do not edit this file as changes may cause incorrect behavior and will be lost +* once the code is regenerated. +* +* @generated by codegen project: GenerateComponentHObjCpp.js +*/ + +#import +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +@protocol RCTEnrichedMarkdownViewProtocol + +@end + +@protocol RCTEnrichedMarkdownTextInputViewProtocol +- (void)focus; +- (void)blur; +- (void)setValue:(NSString *)markdown; +- (void)setSelection:(NSInteger)start end:(NSInteger)end; +- (void)toggleBold; +- (void)toggleItalic; +- (void)toggleUnderline; +- (void)toggleStrikethrough; +- (void)toggleSpoiler; +- (void)setLink:(NSString *)url; +- (void)insertLink:(NSString *)text url:(NSString *)url; +- (void)removeLink; +- (void)requestMarkdown:(NSInteger)requestId; +- (void)requestCaretRect:(NSInteger)requestId; +@end + +RCT_EXTERN inline void RCTEnrichedMarkdownTextInputHandleCommand( + id componentView, + NSString const *commandName, + NSArray const *args) +{ + if ([commandName isEqualToString:@"focus"]) { +#if RCT_DEBUG + if ([args count] != 0) { + RCTLogError(@"%@ command %@ received %d arguments, expected %d.", @"EnrichedMarkdownTextInput", commandName, (int)[args count], 0); + return; + } +#endif + + + + [componentView focus]; + return; +} + +if ([commandName isEqualToString:@"blur"]) { +#if RCT_DEBUG + if ([args count] != 0) { + RCTLogError(@"%@ command %@ received %d arguments, expected %d.", @"EnrichedMarkdownTextInput", commandName, (int)[args count], 0); + return; + } +#endif + + + + [componentView blur]; + return; +} + +if ([commandName isEqualToString:@"setValue"]) { +#if RCT_DEBUG + if ([args count] != 1) { + RCTLogError(@"%@ command %@ received %d arguments, expected %d.", @"EnrichedMarkdownTextInput", commandName, (int)[args count], 1); + return; + } +#endif + + NSObject *arg0 = args[0]; +#if RCT_DEBUG + if (!RCTValidateTypeOfViewCommandArgument(arg0, [NSString class], @"string", @"EnrichedMarkdownTextInput", commandName, @"1st")) { + return; + } +#endif + NSString * markdown = (NSString *)arg0; + + [componentView setValue:markdown]; + return; +} + +if ([commandName isEqualToString:@"setSelection"]) { +#if RCT_DEBUG + if ([args count] != 2) { + RCTLogError(@"%@ command %@ received %d arguments, expected %d.", @"EnrichedMarkdownTextInput", commandName, (int)[args count], 2); + return; + } +#endif + + NSObject *arg0 = args[0]; +#if RCT_DEBUG + if (!RCTValidateTypeOfViewCommandArgument(arg0, [NSNumber class], @"number", @"EnrichedMarkdownTextInput", commandName, @"1st")) { + return; + } +#endif + NSInteger start = [(NSNumber *)arg0 intValue]; + +NSObject *arg1 = args[1]; +#if RCT_DEBUG + if (!RCTValidateTypeOfViewCommandArgument(arg1, [NSNumber class], @"number", @"EnrichedMarkdownTextInput", commandName, @"2nd")) { + return; + } +#endif + NSInteger end = [(NSNumber *)arg1 intValue]; + + [componentView setSelection:start end:end]; + return; +} + +if ([commandName isEqualToString:@"toggleBold"]) { +#if RCT_DEBUG + if ([args count] != 0) { + RCTLogError(@"%@ command %@ received %d arguments, expected %d.", @"EnrichedMarkdownTextInput", commandName, (int)[args count], 0); + return; + } +#endif + + + + [componentView toggleBold]; + return; +} + +if ([commandName isEqualToString:@"toggleItalic"]) { +#if RCT_DEBUG + if ([args count] != 0) { + RCTLogError(@"%@ command %@ received %d arguments, expected %d.", @"EnrichedMarkdownTextInput", commandName, (int)[args count], 0); + return; + } +#endif + + + + [componentView toggleItalic]; + return; +} + +if ([commandName isEqualToString:@"toggleUnderline"]) { +#if RCT_DEBUG + if ([args count] != 0) { + RCTLogError(@"%@ command %@ received %d arguments, expected %d.", @"EnrichedMarkdownTextInput", commandName, (int)[args count], 0); + return; + } +#endif + + + + [componentView toggleUnderline]; + return; +} + +if ([commandName isEqualToString:@"toggleStrikethrough"]) { +#if RCT_DEBUG + if ([args count] != 0) { + RCTLogError(@"%@ command %@ received %d arguments, expected %d.", @"EnrichedMarkdownTextInput", commandName, (int)[args count], 0); + return; + } +#endif + + + + [componentView toggleStrikethrough]; + return; +} + +if ([commandName isEqualToString:@"toggleSpoiler"]) { +#if RCT_DEBUG + if ([args count] != 0) { + RCTLogError(@"%@ command %@ received %d arguments, expected %d.", @"EnrichedMarkdownTextInput", commandName, (int)[args count], 0); + return; + } +#endif + + + + [componentView toggleSpoiler]; + return; +} + +if ([commandName isEqualToString:@"setLink"]) { +#if RCT_DEBUG + if ([args count] != 1) { + RCTLogError(@"%@ command %@ received %d arguments, expected %d.", @"EnrichedMarkdownTextInput", commandName, (int)[args count], 1); + return; + } +#endif + + NSObject *arg0 = args[0]; +#if RCT_DEBUG + if (!RCTValidateTypeOfViewCommandArgument(arg0, [NSString class], @"string", @"EnrichedMarkdownTextInput", commandName, @"1st")) { + return; + } +#endif + NSString * url = (NSString *)arg0; + + [componentView setLink:url]; + return; +} + +if ([commandName isEqualToString:@"insertLink"]) { +#if RCT_DEBUG + if ([args count] != 2) { + RCTLogError(@"%@ command %@ received %d arguments, expected %d.", @"EnrichedMarkdownTextInput", commandName, (int)[args count], 2); + return; + } +#endif + + NSObject *arg0 = args[0]; +#if RCT_DEBUG + if (!RCTValidateTypeOfViewCommandArgument(arg0, [NSString class], @"string", @"EnrichedMarkdownTextInput", commandName, @"1st")) { + return; + } +#endif + NSString * text = (NSString *)arg0; + +NSObject *arg1 = args[1]; +#if RCT_DEBUG + if (!RCTValidateTypeOfViewCommandArgument(arg1, [NSString class], @"string", @"EnrichedMarkdownTextInput", commandName, @"2nd")) { + return; + } +#endif + NSString * url = (NSString *)arg1; + + [componentView insertLink:text url:url]; + return; +} + +if ([commandName isEqualToString:@"removeLink"]) { +#if RCT_DEBUG + if ([args count] != 0) { + RCTLogError(@"%@ command %@ received %d arguments, expected %d.", @"EnrichedMarkdownTextInput", commandName, (int)[args count], 0); + return; + } +#endif + + + + [componentView removeLink]; + return; +} + +if ([commandName isEqualToString:@"requestMarkdown"]) { +#if RCT_DEBUG + if ([args count] != 1) { + RCTLogError(@"%@ command %@ received %d arguments, expected %d.", @"EnrichedMarkdownTextInput", commandName, (int)[args count], 1); + return; + } +#endif + + NSObject *arg0 = args[0]; +#if RCT_DEBUG + if (!RCTValidateTypeOfViewCommandArgument(arg0, [NSNumber class], @"number", @"EnrichedMarkdownTextInput", commandName, @"1st")) { + return; + } +#endif + NSInteger requestId = [(NSNumber *)arg0 intValue]; + + [componentView requestMarkdown:requestId]; + return; +} + +if ([commandName isEqualToString:@"requestCaretRect"]) { +#if RCT_DEBUG + if ([args count] != 1) { + RCTLogError(@"%@ command %@ received %d arguments, expected %d.", @"EnrichedMarkdownTextInput", commandName, (int)[args count], 1); + return; + } +#endif + + NSObject *arg0 = args[0]; +#if RCT_DEBUG + if (!RCTValidateTypeOfViewCommandArgument(arg0, [NSNumber class], @"number", @"EnrichedMarkdownTextInput", commandName, @"1st")) { + return; + } +#endif + NSInteger requestId = [(NSNumber *)arg0 intValue]; + + [componentView requestCaretRect:requestId]; + return; +} + +#if RCT_DEBUG + RCTLogError(@"%@ received command %@, which is not a supported command.", @"EnrichedMarkdownTextInput", commandName); +#endif +} + +@protocol RCTEnrichedMarkdownTextViewProtocol + +@end + +NS_ASSUME_NONNULL_END \ No newline at end of file diff --git a/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/ShadowNodes.cpp b/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/ShadowNodes.cpp new file mode 100644 index 00000000..feadde33 --- /dev/null +++ b/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/ShadowNodes.cpp @@ -0,0 +1,17 @@ + +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateShadowNodeCpp.js + */ + +#include "ShadowNodes.h" + +namespace facebook::react { + + + +} // namespace facebook::react diff --git a/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/ShadowNodes.h b/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/ShadowNodes.h new file mode 100644 index 00000000..615dfa65 --- /dev/null +++ b/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/ShadowNodes.h @@ -0,0 +1,23 @@ + +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateShadowNodeH.js + */ + +#pragma once + +#include "EventEmitters.h" +#include "Props.h" +#include "States.h" +#include +#include + +namespace facebook::react { + + + +} // namespace facebook::react diff --git a/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/States.cpp b/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/States.cpp new file mode 100644 index 00000000..1dbb184c --- /dev/null +++ b/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/States.cpp @@ -0,0 +1,16 @@ + +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateStateCpp.js + */ +#include "States.h" + +namespace facebook::react { + + + +} // namespace facebook::react diff --git a/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/States.h b/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/States.h new file mode 100644 index 00000000..2e55bce7 --- /dev/null +++ b/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/States.h @@ -0,0 +1,20 @@ +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * + * Do not edit this file as changes may cause incorrect behavior and will be lost + * once the code is regenerated. + * + * @generated by codegen project: GenerateStateH.js + */ +#pragma once + +#include +#ifdef RN_SERIALIZABLE_STATE +#include +#endif + +namespace facebook::react { + + + +} // namespace facebook::react \ No newline at end of file diff --git a/ios/input/EnrichedMarkdownTextInput.mm b/ios/input/EnrichedMarkdownTextInput.mm index 96969e8a..3f89fca4 100644 --- a/ios/input/EnrichedMarkdownTextInput.mm +++ b/ios/input/EnrichedMarkdownTextInput.mm @@ -19,10 +19,10 @@ #import #endif -#import -#import -#import -#import +#import "internals/EnrichedMarkdownTextInputComponentDescriptor.h" +#import +#import +#import #import "EnrichedMarkdownTextInputShadowNode.h" #import "RCTFabricComponentsPlugins.h" @@ -292,6 +292,8 @@ - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const & if (newViewProps.selectionColor != oldViewProps.selectionColor) { if (isColorMeaningful(newViewProps.selectionColor)) { ENRMSetSelectionColor(_textView, RCTUIColorFromSharedColor(newViewProps.selectionColor)); + } else { + ENRMSetSelectionColor(_textView, nil); } } diff --git a/ios/input/internals/EnrichedMarkdownTextInputShadowNode.h b/ios/input/internals/EnrichedMarkdownTextInputShadowNode.h index 1488126f..6a900d12 100644 --- a/ios/input/internals/EnrichedMarkdownTextInputShadowNode.h +++ b/ios/input/internals/EnrichedMarkdownTextInputShadowNode.h @@ -1,7 +1,7 @@ #pragma once #include "EnrichedMarkdownTextInputState.h" -#include -#include +#include +#include #include #include diff --git a/ios/internals/EnrichedMarkdownShadowNode.h b/ios/internals/EnrichedMarkdownShadowNode.h index 656ae5b4..b4b13a21 100644 --- a/ios/internals/EnrichedMarkdownShadowNode.h +++ b/ios/internals/EnrichedMarkdownShadowNode.h @@ -1,8 +1,8 @@ #pragma once #include "MeasurementCache.h" -#include -#include -#include +#include "EnrichedMarkdownState.h" +#include +#include #include #include diff --git a/ios/internals/EnrichedMarkdownTextShadowNode.h b/ios/internals/EnrichedMarkdownTextShadowNode.h index b3523ede..96b2ff86 100644 --- a/ios/internals/EnrichedMarkdownTextShadowNode.h +++ b/ios/internals/EnrichedMarkdownTextShadowNode.h @@ -1,8 +1,8 @@ #pragma once #include "MeasurementCache.h" -#include -#include -#include +#include "EnrichedMarkdownTextState.h" +#include +#include #include #include diff --git a/ios/renderer/LinkRenderer.h b/ios/renderer/LinkRenderer.h index ff5b8d20..b784b0af 100644 --- a/ios/renderer/LinkRenderer.h +++ b/ios/renderer/LinkRenderer.h @@ -2,6 +2,16 @@ #import "NodeRenderer.h" #import "RenderContext.h" +/** + * Attribute names used by the link/mention/citation renderer to tag ranges of + * the rendered NSAttributedString. Tap dispatching reads these to decide which + * JS event to fire for a given character. + */ +FOUNDATION_EXPORT NSString *const ENRMMentionURLAttributeName; +FOUNDATION_EXPORT NSString *const ENRMMentionTextAttributeName; +FOUNDATION_EXPORT NSString *const ENRMCitationURLAttributeName; +FOUNDATION_EXPORT NSString *const ENRMCitationTextAttributeName; + @interface LinkRenderer : NSObject - (instancetype)initWithRendererFactory:(id)rendererFactory config:(id)config; @end diff --git a/ios/renderer/LinkRenderer.m b/ios/renderer/LinkRenderer.m index 8c37b26d..f7353a21 100644 --- a/ios/renderer/LinkRenderer.m +++ b/ios/renderer/LinkRenderer.m @@ -5,6 +5,14 @@ #import "StyleConfig.h" #import +NSString *const ENRMMentionURLAttributeName = @"ENRMMentionURL"; +NSString *const ENRMMentionTextAttributeName = @"ENRMMentionText"; +NSString *const ENRMCitationURLAttributeName = @"ENRMCitationURL"; +NSString *const ENRMCitationTextAttributeName = @"ENRMCitationText"; + +static NSString *const kMentionScheme = @"mention://"; +static NSString *const kCitationScheme = @"citation://"; + @implementation LinkRenderer { RendererFactory *_rendererFactory; StyleConfig *_config; @@ -20,41 +28,109 @@ - (instancetype)initWithRendererFactory:(id)rendererFactory config:(id)config return self; } +#pragma mark - Scheme helpers + +static BOOL isMentionURL(NSString *url) +{ + return [url hasPrefix:kMentionScheme]; +} + +static BOOL isCitationURL(NSString *url) +{ + return [url hasPrefix:kCitationScheme]; +} + +static NSString *stripScheme(NSString *url, NSString *scheme) +{ + if ([url hasPrefix:scheme]) { + return [url substringFromIndex:scheme.length]; + } + return url; +} + +// Stamps NSKern on the character before and the last character of an inline +// chip range so its drawn background never overlaps surrounding text. +// +// Kern value is `paddingHorizontal`: exactly enough to shift the chip's left +// overhang off the previous glyph (leading kern) and the following glyph off +// the chip's right overhang (trailing kern). With this amount, a chip just +// touches its neighbors rather than gapping — adjacent chips separated by a +// source-markdown space show the natural `space_width` between them, which +// matches the gap CSS `paddingInline` produces on web. Using `paddingHorizontal +// * 2` would double up across a shared boundary character and push consecutive +// chips visibly far apart. +// +// Adjacent chips writing the same value on the shared boundary character is +// idempotent. +static void applyChipKern(NSMutableAttributedString *output, NSRange chipRange, CGFloat paddingHorizontal) +{ + if (chipRange.length == 0 || paddingHorizontal <= 0) + return; + + NSNumber *kernValue = @(paddingHorizontal); + + // Trailing kern on the last glyph of the chip. + NSRange trailing = NSMakeRange(NSMaxRange(chipRange) - 1, 1); + [output addAttribute:NSKernAttributeName value:kernValue range:trailing]; + + // Leading kern on the character immediately before the chip, if any. This + // pushes the chip right so its left overhang doesn't cover preceding text. + if (chipRange.location > 0) { + NSRange leading = NSMakeRange(chipRange.location - 1, 1); + [output addAttribute:NSKernAttributeName value:kernValue range:leading]; + } +} + #pragma mark - Rendering - (void)renderNode:(MarkdownASTNode *)node into:(NSMutableAttributedString *)output context:(RenderContext *)context +{ + NSString *url = node.attributes[@"url"] ?: @""; + + if (isMentionURL(url)) { + [self renderMentionNode:node url:url into:output context:context]; + return; + } + + if (isCitationURL(url)) { + [self renderCitationNode:node url:url into:output context:context]; + return; + } + + [self renderLinkNode:node url:url into:output context:context]; +} + +#pragma mark - Link (default / existing behavior) + +- (void)renderLinkNode:(MarkdownASTNode *)node + url:(NSString *)url + into:(NSMutableAttributedString *)output + context:(RenderContext *)context { NSUInteger start = output.length; - // 1. Render children first to establish base attributes [_rendererFactory renderChildrenOfNode:node into:output context:context]; NSRange range = NSMakeRange(start, output.length - start); if (range.length == 0) return; - // 2. Extract configuration - NSString *url = node.attributes[@"url"] ?: @""; RCTUIColor *linkColor = [_config linkColor]; NSNumber *underlineStyle = @([_config linkUnderline] ? NSUnderlineStyleSingle : NSUnderlineStyleNone); NSString *linkFontFamily = [_config linkFontFamily]; - // 3. Apply core link functionality (non-destructive) [output addAttribute:NSLinkAttributeName value:url range:range]; - // 4. Optimize visual attributes via enumeration to avoid redundant updates [output enumerateAttributesInRange:range options:NSAttributedStringEnumerationLongestEffectiveRangeNotRequired usingBlock:^(NSDictionary *attrs, NSRange subrange, BOOL *stop) { NSMutableDictionary *newAttributes = [NSMutableDictionary dictionary]; - // Only apply link color if the subrange isn't already colored by the link style if (linkColor && ![attrs[NSForegroundColorAttributeName] isEqual:linkColor]) { newAttributes[NSForegroundColorAttributeName] = linkColor; newAttributes[NSUnderlineColorAttributeName] = linkColor; } - // Only update underline style if it differs from the config if (![attrs[NSUnderlineStyleAttributeName] isEqual:underlineStyle]) { newAttributes[NSUnderlineStyleAttributeName] = underlineStyle; } @@ -80,8 +156,142 @@ - (void)renderNode:(MarkdownASTNode *)node into:(NSMutableAttributedString *)out } }]; - // 5. Register for touch handling [context registerLinkRange:range url:url]; } -@end \ No newline at end of file +#pragma mark - Mention + +- (void)renderMentionNode:(MarkdownASTNode *)node + url:(NSString *)url + into:(NSMutableAttributedString *)output + context:(RenderContext *)context +{ + // Collapse children into a plain display string. The pill itself is rendered + // as inline text (not an NSTextAttachment), so native copy/paste/selection + // behave exactly like normal text — the "pill" look is painted by + // `MentionBackground` during the layout manager's draw cycle. + NSMutableAttributedString *childBuffer = [[NSMutableAttributedString alloc] init]; + [_rendererFactory renderChildrenOfNode:node into:childBuffer context:context]; + NSString *displayText = childBuffer.string ?: @""; + if (displayText.length == 0) + return; + + NSString *mentionURL = stripScheme(url, kMentionScheme); + + // Inherit surrounding paragraph attributes so the pill text participates in + // the current line's metrics. + NSDictionary *baseAttrs = output.length > 0 ? [output attributesAtIndex:output.length - 1 effectiveRange:NULL] : @{}; + NSMutableDictionary *attrs = [NSMutableDictionary dictionaryWithDictionary:baseAttrs]; + + UIFont *mentionFont = [_config mentionFont]; + if (mentionFont) { + attrs[NSFontAttributeName] = mentionFont; + } + RCTUIColor *mentionColor = [_config mentionColor]; + if (mentionColor) { + attrs[NSForegroundColorAttributeName] = mentionColor; + } + attrs[ENRMMentionURLAttributeName] = mentionURL; + attrs[ENRMMentionTextAttributeName] = displayText; + + NSUInteger start = output.length; + [output appendAttributedString:[[NSAttributedString alloc] initWithString:displayText attributes:attrs]]; + NSRange outputRange = NSMakeRange(start, output.length - start); + + // The drawn pill extends `paddingHorizontal` beyond the glyph run on both + // sides. Inline text doesn't reserve any advance for that visual padding, so + // without extra spacing the pill would cover the character immediately + // before the mention (and likewise any adjacent mention/citation following + // it). Stamping NSKern on: + // - the character BEFORE the mention (adds leading advance), and + // - the LAST character of the mention (adds trailing advance) + // pushes the surrounding text outside the pill edges, matching what CSS + // `paddingInline` produces on web. Adjacent chips' kerns land on the same + // boundary character and are idempotent. + CGFloat mentionPaddingH = [_config mentionPaddingHorizontal]; + if (mentionPaddingH > 0 && outputRange.length > 0) { + applyChipKern(output, outputRange, mentionPaddingH); + } + + [context registerMentionRange:outputRange url:mentionURL text:displayText]; +} + +#pragma mark - Citation + +- (void)renderCitationNode:(MarkdownASTNode *)node + url:(NSString *)url + into:(NSMutableAttributedString *)output + context:(RenderContext *)context +{ + NSUInteger start = output.length; + [_rendererFactory renderChildrenOfNode:node into:output context:context]; + NSRange range = NSMakeRange(start, output.length - start); + if (range.length == 0) + return; + + NSString *targetURL = stripScheme(url, kCitationScheme); + NSString *labelText = [[output attributedSubstringFromRange:range] string] ?: @""; + + CGFloat multiplier = [_config citationFontSizeMultiplier]; + CGFloat baselineOffsetPx = [_config citationBaselineOffsetPx]; + RCTUIColor *citationColor = [_config citationColor]; + NSString *fontWeight = [_config citationFontWeight]; + BOOL underline = [_config citationUnderline]; + CGFloat paddingHorizontal = [_config citationPaddingHorizontal]; + + [output enumerateAttributesInRange:range + options:NSAttributedStringEnumerationLongestEffectiveRangeNotRequired + usingBlock:^(NSDictionary *attrs, NSRange subrange, BOOL *stop) { + NSMutableDictionary *newAttributes = [NSMutableDictionary dictionary]; + + UIFont *currentFont = attrs[NSFontAttributeName]; + if (currentFont && multiplier > 0) { + CGFloat newSize = currentFont.pointSize * multiplier; + UIFont *scaled = [RCTFont updateFont:currentFont + withFamily:nil + size:@(newSize) + weight:fontWeight.length > 0 ? fontWeight : nil + style:nil + variant:nil + scaleMultiplier:1.0]; + if (scaled) { + newAttributes[NSFontAttributeName] = scaled; + + CGFloat offset = baselineOffsetPx; + if (offset == 0) { + offset = (currentFont.capHeight - scaled.capHeight) * 0.5; + } + newAttributes[NSBaselineOffsetAttributeName] = @(offset); + } + } else if (baselineOffsetPx != 0) { + newAttributes[NSBaselineOffsetAttributeName] = @(baselineOffsetPx); + } + + if (citationColor) { + newAttributes[NSForegroundColorAttributeName] = citationColor; + } + + if (underline) { + newAttributes[NSUnderlineStyleAttributeName] = @(NSUnderlineStyleSingle); + if (citationColor) { + newAttributes[NSUnderlineColorAttributeName] = citationColor; + } + } + + if (newAttributes.count > 0) { + [output addAttributes:newAttributes range:subrange]; + } + }]; + + [output addAttribute:ENRMCitationURLAttributeName value:targetURL range:range]; + [output addAttribute:ENRMCitationTextAttributeName value:labelText range:range]; + + // Stamp NSKern on the characters flanking the chip so the drawn background + // has symmetric clearance from surrounding text (previous glyph on the + // left, following glyph on the right). + applyChipKern(output, range, paddingHorizontal); + + [context registerCitationRange:range url:targetURL text:labelText]; +} + +@end diff --git a/ios/renderer/RenderContext.h b/ios/renderer/RenderContext.h index c7aa2b01..ef3e7202 100644 --- a/ios/renderer/RenderContext.h +++ b/ios/renderer/RenderContext.h @@ -25,6 +25,12 @@ typedef NS_ENUM(NSInteger, ListType) { ListTypeUnordered, ListTypeOrdered }; @interface RenderContext : NSObject @property (nonatomic, strong) NSMutableArray *linkRanges; @property (nonatomic, strong) NSMutableArray *linkURLs; +@property (nonatomic, strong) NSMutableArray *mentionRanges; +@property (nonatomic, strong) NSMutableArray *mentionURLs; +@property (nonatomic, strong) NSMutableArray *mentionTexts; +@property (nonatomic, strong) NSMutableArray *citationRanges; +@property (nonatomic, strong) NSMutableArray *citationURLs; +@property (nonatomic, strong) NSMutableArray *citationTexts; @property (nonatomic, strong) NSMutableArray *headingRanges; @property (nonatomic, strong) NSMutableArray *headingLevels; @property (nonatomic, strong) NSMutableArray *imageRanges; @@ -53,6 +59,8 @@ typedef NS_ENUM(NSInteger, ListType) { ListTypeUnordered, ListTypeOrdered }; - (NSMutableParagraphStyle *)spacerStyleWithHeight:(CGFloat)height spacing:(CGFloat)spacing; - (NSMutableParagraphStyle *)blockSpacerStyleWithMargin:(CGFloat)margin; - (void)registerLinkRange:(NSRange)range url:(NSString *)url; +- (void)registerMentionRange:(NSRange)range url:(NSString *)url text:(NSString *)text; +- (void)registerCitationRange:(NSRange)range url:(NSString *)url text:(NSString *)text; - (void)applyLinkAttributesToString:(NSMutableAttributedString *)attributedString; - (void)registerHeadingRange:(NSRange)range level:(NSInteger)level text:(NSString *)text; diff --git a/ios/renderer/RenderContext.m b/ios/renderer/RenderContext.m index 68a6ff48..6e0336c3 100644 --- a/ios/renderer/RenderContext.m +++ b/ios/renderer/RenderContext.m @@ -17,6 +17,12 @@ - (instancetype)init if (self = [super init]) { _linkRanges = [NSMutableArray array]; _linkURLs = [NSMutableArray array]; + _mentionRanges = [NSMutableArray array]; + _mentionURLs = [NSMutableArray array]; + _mentionTexts = [NSMutableArray array]; + _citationRanges = [NSMutableArray array]; + _citationURLs = [NSMutableArray array]; + _citationTexts = [NSMutableArray array]; _headingRanges = [NSMutableArray array]; _headingLevels = [NSMutableArray array]; _imageRanges = [NSMutableArray array]; @@ -105,6 +111,24 @@ - (void)registerLinkRange:(NSRange)range url:(NSString *)url [self.linkURLs addObject:url ?: @""]; } +- (void)registerMentionRange:(NSRange)range url:(NSString *)url text:(NSString *)text +{ + if (range.length == 0) + return; + [self.mentionRanges addObject:[NSValue valueWithRange:range]]; + [self.mentionURLs addObject:url ?: @""]; + [self.mentionTexts addObject:text ?: @""]; +} + +- (void)registerCitationRange:(NSRange)range url:(NSString *)url text:(NSString *)text +{ + if (range.length == 0) + return; + [self.citationRanges addObject:[NSValue valueWithRange:range]]; + [self.citationURLs addObject:url ?: @""]; + [self.citationTexts addObject:text ?: @""]; +} + - (void)applyLinkAttributesToString:(NSMutableAttributedString *)attributedString { NSUInteger length = attributedString.length; @@ -243,6 +267,12 @@ - (void)reset { [_linkRanges removeAllObjects]; [_linkURLs removeAllObjects]; + [_mentionRanges removeAllObjects]; + [_mentionURLs removeAllObjects]; + [_mentionTexts removeAllObjects]; + [_citationRanges removeAllObjects]; + [_citationURLs removeAllObjects]; + [_citationTexts removeAllObjects]; [_headingRanges removeAllObjects]; [_headingLevels removeAllObjects]; [_imageRanges removeAllObjects]; diff --git a/ios/styles/StyleConfig.h b/ios/styles/StyleConfig.h index f9746c4a..929eaec5 100644 --- a/ios/styles/StyleConfig.h +++ b/ios/styles/StyleConfig.h @@ -367,5 +367,52 @@ - (void)setSpoilerParticleSpeed:(CGFloat)newValue; - (CGFloat)spoilerSolidBorderRadius; - (void)setSpoilerSolidBorderRadius:(CGFloat)newValue; +// Mention properties +- (RCTUIColor *)mentionColor; +- (void)setMentionColor:(RCTUIColor *)newValue; +- (RCTUIColor *)mentionBackgroundColor; +- (void)setMentionBackgroundColor:(RCTUIColor *)newValue; +- (RCTUIColor *)mentionBorderColor; +- (void)setMentionBorderColor:(RCTUIColor *)newValue; +- (CGFloat)mentionBorderWidth; +- (void)setMentionBorderWidth:(CGFloat)newValue; +- (CGFloat)mentionBorderRadius; +- (void)setMentionBorderRadius:(CGFloat)newValue; +- (CGFloat)mentionPaddingHorizontal; +- (void)setMentionPaddingHorizontal:(CGFloat)newValue; +- (CGFloat)mentionPaddingVertical; +- (void)setMentionPaddingVertical:(CGFloat)newValue; +- (NSString *)mentionFontFamily; +- (void)setMentionFontFamily:(NSString *)newValue; +- (NSString *)mentionFontWeight; +- (void)setMentionFontWeight:(NSString *)newValue; +- (CGFloat)mentionFontSize; +- (void)setMentionFontSize:(CGFloat)newValue; +- (CGFloat)mentionPressedOpacity; +- (void)setMentionPressedOpacity:(CGFloat)newValue; +- (UIFont *)mentionFont; +// Citation properties +- (RCTUIColor *)citationColor; +- (void)setCitationColor:(RCTUIColor *)newValue; +- (CGFloat)citationFontSizeMultiplier; +- (void)setCitationFontSizeMultiplier:(CGFloat)newValue; +- (CGFloat)citationBaselineOffsetPx; +- (void)setCitationBaselineOffsetPx:(CGFloat)newValue; +- (NSString *)citationFontWeight; +- (void)setCitationFontWeight:(NSString *)newValue; +- (BOOL)citationUnderline; +- (void)setCitationUnderline:(BOOL)newValue; +- (RCTUIColor *)citationBackgroundColor; +- (void)setCitationBackgroundColor:(RCTUIColor *)newValue; +- (CGFloat)citationPaddingHorizontal; +- (void)setCitationPaddingHorizontal:(CGFloat)newValue; +- (CGFloat)citationPaddingVertical; +- (void)setCitationPaddingVertical:(CGFloat)newValue; +- (RCTUIColor *)citationBorderColor; +- (void)setCitationBorderColor:(RCTUIColor *)newValue; +- (CGFloat)citationBorderWidth; +- (void)setCitationBorderWidth:(CGFloat)newValue; +- (CGFloat)citationBorderRadius; +- (void)setCitationBorderRadius:(CGFloat)newValue; @end diff --git a/ios/styles/StyleConfig.mm b/ios/styles/StyleConfig.mm index 964ca1d4..bb77c2ba 100644 --- a/ios/styles/StyleConfig.mm +++ b/ios/styles/StyleConfig.mm @@ -227,6 +227,32 @@ @implementation StyleConfig { CGFloat _spoilerParticleDensity; CGFloat _spoilerParticleSpeed; CGFloat _spoilerSolidBorderRadius; + // Mention properties + RCTUIColor *_mentionColor; + RCTUIColor *_mentionBackgroundColor; + RCTUIColor *_mentionBorderColor; + CGFloat _mentionBorderWidth; + CGFloat _mentionBorderRadius; + CGFloat _mentionPaddingHorizontal; + CGFloat _mentionPaddingVertical; + NSString *_mentionFontFamily; + NSString *_mentionFontWeight; + CGFloat _mentionFontSize; + CGFloat _mentionPressedOpacity; + UIFont *_mentionFont; + BOOL _mentionFontNeedsRecreation; + // Citation properties + RCTUIColor *_citationColor; + CGFloat _citationFontSizeMultiplier; + CGFloat _citationBaselineOffsetPx; + NSString *_citationFontWeight; + BOOL _citationUnderline; + RCTUIColor *_citationBackgroundColor; + CGFloat _citationPaddingHorizontal; + CGFloat _citationPaddingVertical; + RCTUIColor *_citationBorderColor; + CGFloat _citationBorderWidth; + CGFloat _citationBorderRadius; } - (instancetype)init @@ -256,6 +282,9 @@ - (instancetype)init _tableFontNeedsRecreation = YES; _tableHeaderFontNeedsRecreation = YES; _linkUnderline = YES; + _mentionFontNeedsRecreation = YES; + _citationFontSizeMultiplier = 0.7; + _mentionPressedOpacity = 0.6; return self; } @@ -283,6 +312,7 @@ - (void)setFontScaleMultiplier:(CGFloat)newValue _codeBlockFontNeedsRecreation = YES; _blockquoteFontNeedsRecreation = YES; _tableFontNeedsRecreation = YES; + _mentionFontNeedsRecreation = YES; } } @@ -317,6 +347,7 @@ - (void)setMaxFontSizeMultiplier:(CGFloat)newValue _codeBlockFontNeedsRecreation = YES; _blockquoteFontNeedsRecreation = YES; _tableFontNeedsRecreation = YES; + _mentionFontNeedsRecreation = YES; } } @@ -498,6 +529,30 @@ - (id)copyWithZone:(NSZone *)zone copy->_spoilerParticleSpeed = _spoilerParticleSpeed; copy->_spoilerSolidBorderRadius = _spoilerSolidBorderRadius; + copy->_mentionColor = [_mentionColor copy]; + copy->_mentionBackgroundColor = [_mentionBackgroundColor copy]; + copy->_mentionBorderColor = [_mentionBorderColor copy]; + copy->_mentionBorderWidth = _mentionBorderWidth; + copy->_mentionBorderRadius = _mentionBorderRadius; + copy->_mentionPaddingHorizontal = _mentionPaddingHorizontal; + copy->_mentionPaddingVertical = _mentionPaddingVertical; + copy->_mentionFontFamily = [_mentionFontFamily copy]; + copy->_mentionFontWeight = [_mentionFontWeight copy]; + copy->_mentionFontSize = _mentionFontSize; + copy->_mentionPressedOpacity = _mentionPressedOpacity; + copy->_mentionFontNeedsRecreation = YES; + copy->_citationColor = [_citationColor copy]; + copy->_citationFontSizeMultiplier = _citationFontSizeMultiplier; + copy->_citationBaselineOffsetPx = _citationBaselineOffsetPx; + copy->_citationFontWeight = [_citationFontWeight copy]; + copy->_citationUnderline = _citationUnderline; + copy->_citationBackgroundColor = [_citationBackgroundColor copy]; + copy->_citationPaddingHorizontal = _citationPaddingHorizontal; + copy->_citationPaddingVertical = _citationPaddingVertical; + copy->_citationBorderColor = [_citationBorderColor copy]; + copy->_citationBorderWidth = _citationBorderWidth; + copy->_citationBorderRadius = _citationBorderRadius; + return copy; } @@ -2406,4 +2461,251 @@ - (void)setSpoilerSolidBorderRadius:(CGFloat)newValue _spoilerSolidBorderRadius = newValue; } +// ── Mention ───────────────────────────────────────────────────────────── + +- (RCTUIColor *)mentionColor +{ + return _mentionColor; +} + +- (void)setMentionColor:(RCTUIColor *)newValue +{ + _mentionColor = newValue; +} + +- (RCTUIColor *)mentionBackgroundColor +{ + return _mentionBackgroundColor; +} + +- (void)setMentionBackgroundColor:(RCTUIColor *)newValue +{ + _mentionBackgroundColor = newValue; +} + +- (RCTUIColor *)mentionBorderColor +{ + return _mentionBorderColor; +} + +- (void)setMentionBorderColor:(RCTUIColor *)newValue +{ + _mentionBorderColor = newValue; +} + +- (CGFloat)mentionBorderWidth +{ + return _mentionBorderWidth; +} + +- (void)setMentionBorderWidth:(CGFloat)newValue +{ + _mentionBorderWidth = newValue; +} + +- (CGFloat)mentionBorderRadius +{ + return _mentionBorderRadius; +} + +- (void)setMentionBorderRadius:(CGFloat)newValue +{ + _mentionBorderRadius = newValue; +} + +- (CGFloat)mentionPaddingHorizontal +{ + return _mentionPaddingHorizontal; +} + +- (void)setMentionPaddingHorizontal:(CGFloat)newValue +{ + _mentionPaddingHorizontal = newValue; +} + +- (CGFloat)mentionPaddingVertical +{ + return _mentionPaddingVertical; +} + +- (void)setMentionPaddingVertical:(CGFloat)newValue +{ + _mentionPaddingVertical = newValue; +} + +- (NSString *)mentionFontFamily +{ + return _mentionFontFamily; +} + +- (void)setMentionFontFamily:(NSString *)newValue +{ + _mentionFontFamily = newValue; + _mentionFontNeedsRecreation = YES; +} + +- (NSString *)mentionFontWeight +{ + return _mentionFontWeight; +} + +- (void)setMentionFontWeight:(NSString *)newValue +{ + _mentionFontWeight = newValue; + _mentionFontNeedsRecreation = YES; +} + +- (CGFloat)mentionFontSize +{ + return _mentionFontSize; +} + +- (void)setMentionFontSize:(CGFloat)newValue +{ + _mentionFontSize = newValue; + _mentionFontNeedsRecreation = YES; +} + +- (CGFloat)mentionPressedOpacity +{ + return _mentionPressedOpacity; +} + +- (void)setMentionPressedOpacity:(CGFloat)newValue +{ + _mentionPressedOpacity = newValue; +} + +- (UIFont *)mentionFont +{ + if (_mentionFontNeedsRecreation || !_mentionFont) { + // Fall back to paragraph font size when mention.fontSize is 0 (inherit). + CGFloat size = _mentionFontSize > 0 ? _mentionFontSize : _paragraphFontSize; + if (size <= 0) { + size = 16; + } + _mentionFont = [RCTFont updateFont:nil + withFamily:_mentionFontFamily + size:@(size) + weight:normalizedFontWeight(_mentionFontWeight) + style:nil + variant:nil + scaleMultiplier:[self effectiveScaleMultiplierForFontSize:size]]; + _mentionFontNeedsRecreation = NO; + } + return _mentionFont; +} + +// ── Citation ──────────────────────────────────────────────────────────── + +- (RCTUIColor *)citationColor +{ + return _citationColor; +} + +- (void)setCitationColor:(RCTUIColor *)newValue +{ + _citationColor = newValue; +} + +- (CGFloat)citationFontSizeMultiplier +{ + return _citationFontSizeMultiplier > 0 ? _citationFontSizeMultiplier : 0.7; +} + +- (void)setCitationFontSizeMultiplier:(CGFloat)newValue +{ + _citationFontSizeMultiplier = newValue; +} + +- (CGFloat)citationBaselineOffsetPx +{ + return _citationBaselineOffsetPx; +} + +- (void)setCitationBaselineOffsetPx:(CGFloat)newValue +{ + _citationBaselineOffsetPx = newValue; +} + +- (NSString *)citationFontWeight +{ + return _citationFontWeight; +} + +- (void)setCitationFontWeight:(NSString *)newValue +{ + _citationFontWeight = newValue; +} + +- (BOOL)citationUnderline +{ + return _citationUnderline; +} + +- (void)setCitationUnderline:(BOOL)newValue +{ + _citationUnderline = newValue; +} + +- (RCTUIColor *)citationBackgroundColor +{ + return _citationBackgroundColor; +} + +- (void)setCitationBackgroundColor:(RCTUIColor *)newValue +{ + _citationBackgroundColor = newValue; +} + +- (CGFloat)citationPaddingHorizontal +{ + return _citationPaddingHorizontal; +} + +- (void)setCitationPaddingHorizontal:(CGFloat)newValue +{ + _citationPaddingHorizontal = newValue; +} + +- (CGFloat)citationPaddingVertical +{ + return _citationPaddingVertical; +} + +- (void)setCitationPaddingVertical:(CGFloat)newValue +{ + _citationPaddingVertical = newValue; +} + +- (RCTUIColor *)citationBorderColor +{ + return _citationBorderColor; +} + +- (void)setCitationBorderColor:(RCTUIColor *)newValue +{ + _citationBorderColor = newValue; +} + +- (CGFloat)citationBorderWidth +{ + return _citationBorderWidth; +} + +- (void)setCitationBorderWidth:(CGFloat)newValue +{ + _citationBorderWidth = newValue; +} + +- (CGFloat)citationBorderRadius +{ + return _citationBorderRadius; +} + +- (void)setCitationBorderRadius:(CGFloat)newValue +{ + _citationBorderRadius = newValue; +} + @end diff --git a/ios/utils/CitationBackground.h b/ios/utils/CitationBackground.h new file mode 100644 index 00000000..9aaff123 --- /dev/null +++ b/ios/utils/CitationBackground.h @@ -0,0 +1,24 @@ +#pragma once +#import "ENRMUIKit.h" +#import "StyleConfig.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + * Draws the padded rounded background behind any glyph range tagged with + * `ENRMCitationURLAttributeName`. Inline-text rendering of citations means + * copy/paste work naturally; the pill appearance is achieved purely by this + * background pass inside the NSLayoutManager draw cycle. + */ +@interface CitationBackground : NSObject + +- (instancetype)initWithConfig:(StyleConfig *)config; + +- (void)drawBackgroundsForGlyphRange:(NSRange)glyphsToShow + layoutManager:(NSLayoutManager *)layoutManager + textContainer:(NSTextContainer *)textContainer + atPoint:(CGPoint)origin; + +@end + +NS_ASSUME_NONNULL_END diff --git a/ios/utils/CitationBackground.m b/ios/utils/CitationBackground.m new file mode 100644 index 00000000..c04c1574 --- /dev/null +++ b/ios/utils/CitationBackground.m @@ -0,0 +1,158 @@ +#import "CitationBackground.h" +#import "ENRMUIKit.h" +#import "LinkRenderer.h" + +@implementation CitationBackground { + StyleConfig *_config; +} + +- (instancetype)initWithConfig:(StyleConfig *)config +{ + self = [super init]; + if (self) { + _config = config; + } + return self; +} + +- (void)drawBackgroundsForGlyphRange:(NSRange)glyphsToShow + layoutManager:(NSLayoutManager *)layoutManager + textContainer:(NSTextContainer *)textContainer + atPoint:(CGPoint)origin +{ + NSTextStorage *textStorage = layoutManager.textStorage; + if (!textStorage || textStorage.length == 0) + return; + + NSRange charRange = [layoutManager characterRangeForGlyphRange:glyphsToShow actualGlyphRange:NULL]; + if (charRange.location == NSNotFound || charRange.length == 0) + return; + + RCTUIColor *bgColor = [_config citationBackgroundColor]; + CGFloat paddingH = [_config citationPaddingHorizontal]; + CGFloat paddingV = [_config citationPaddingVertical]; + RCTUIColor *borderColor = [_config citationBorderColor]; + CGFloat borderWidth = [_config citationBorderWidth]; + CGFloat borderRadius = [_config citationBorderRadius]; + + // Nothing to paint when neither a fill nor a stroke would be visible. + if (!bgColor && (!borderColor || borderWidth <= 0)) + return; + + NSUInteger totalGlyphs = [layoutManager numberOfGlyphs]; + + [textStorage + enumerateAttribute:ENRMCitationURLAttributeName + inRange:NSMakeRange(0, textStorage.length) + options:0 + usingBlock:^(id value, NSRange range, BOOL *stop) { + if (!value || range.length == 0) + return; + if (NSIntersectionRange(range, charRange).length == 0) + return; + + NSRange glyphRange = [layoutManager glyphRangeForCharacterRange:range actualCharacterRange:NULL]; + if (glyphRange.location == NSNotFound || glyphRange.length == 0) + return; + + // Pick up the font actually applied to the citation glyphs so the + // chip can be sized to the (smaller) citation font, not the full + // line height. + UIFont *citationFont = [textStorage attribute:NSFontAttributeName + atIndex:range.location + effectiveRange:NULL]; + + [layoutManager + enumerateLineFragmentsForGlyphRange:glyphRange + usingBlock:^(CGRect lineRect, CGRect usedRect, NSTextContainer *tc, + NSRange lineRange, BOOL *lineStop) { + NSRange intersect = NSIntersectionRange(lineRange, glyphRange); + if (intersect.length == 0) + return; + + // Horizontal extent: compute from glyph ADVANCE positions + // (not ink bounds) so the chip hugs each digit the same + // way proportional text naturally lays out. Using + // boundingRectForGlyphRange: here would include any + // trailing kerning we added to space consecutive chips + // apart, causing them to visually overlap. + NSUInteger firstGlyph = intersect.location; + NSUInteger lastGlyph = NSMaxRange(intersect) - 1; + + CGPoint firstLoc = [layoutManager locationForGlyphAtIndex:firstGlyph]; + CGFloat chipLeftX = lineRect.origin.x + firstLoc.x; + + CGFloat chipRightX; + NSUInteger afterLastGlyph = NSMaxRange(intersect); + BOOL canQueryNext = (afterLastGlyph < totalGlyphs) && + (afterLastGlyph < NSMaxRange(lineRange)); + if (canQueryNext) { + CGPoint nextLoc = + [layoutManager locationForGlyphAtIndex:afterLastGlyph]; + chipRightX = lineRect.origin.x + nextLoc.x; + + // Subtract any trailing kern we stamped on the last + // character of the citation so the chip doesn't include + // that spacing gap. + NSUInteger lastCharIndex = + [layoutManager characterIndexForGlyphAtIndex:lastGlyph]; + if (lastCharIndex < textStorage.length) { + NSNumber *kern = [textStorage attribute:NSKernAttributeName + atIndex:lastCharIndex + effectiveRange:NULL]; + if (kern) { + chipRightX -= [kern doubleValue]; + } + } + } else { + // Last glyph on the line or last in the buffer — fall + // back to the last glyph's ink bounding rect (trailing + // kerning is irrelevant here since there's nothing + // after it). + CGRect lastRect = + [layoutManager boundingRectForGlyphRange:NSMakeRange(lastGlyph, 1) + inTextContainer:textContainer]; + chipRightX = lastRect.origin.x + lastRect.size.width; + } + + // Vertical extent: derive from the citation glyphs' own + // baseline + font metrics so the chip hugs the smaller + // superscript text rather than stretching to the line + // height. `locationForGlyphAtIndex:` returns the baseline + // in the line fragment's coordinate system and already + // accounts for NSBaselineOffsetAttributeName. + CGFloat baselineY = lineRect.origin.y + firstLoc.y; + + CGFloat ascent = citationFont ? citationFont.ascender : 0; + // UIFont.descender is negative (points below baseline); + // subtract it to move downward from the baseline. + CGFloat descent = citationFont ? citationFont.descender : 0; + + CGFloat chipTop = baselineY - ascent - paddingV; + CGFloat chipBottom = baselineY - descent + paddingV; + + CGRect chipRect = + CGRectMake(chipLeftX + origin.x - paddingH, chipTop + origin.y, + MAX(0, (chipRightX - chipLeftX)) + paddingH * 2, + MAX(0, chipBottom - chipTop)); + + CGFloat maxRadius = MIN(chipRect.size.width, chipRect.size.height) / 2.0; + CGFloat radius = MIN(borderRadius, maxRadius); + UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:chipRect + cornerRadius:radius]; + + if (bgColor) { + [bgColor setFill]; + [path fill]; + } + + if (borderColor && borderWidth > 0) { + path.lineWidth = borderWidth; + [borderColor setStroke]; + [path stroke]; + } + }]; + }]; +} + +@end diff --git a/ios/utils/LinkTapUtils.h b/ios/utils/LinkTapUtils.h index f7b6c188..a0eced0a 100644 --- a/ios/utils/LinkTapUtils.h +++ b/ios/utils/LinkTapUtils.h @@ -14,7 +14,17 @@ NSString *_Nullable linkURLAtTapLocation(ENRMPlatformTextView *textView, ENRMTap /// Returns the link URL at the given character range, or nil if none found. NSString *_Nullable linkURLAtRange(ENRMPlatformTextView *textView, NSRange characterRange); -/// Returns YES if the point (in textView coordinates) is on a link or task list checkbox. +/// Returns the inline element (link, mention, or citation) at the tap location. +/// The out parameters are populated only when a matching element is present. +/// Returns YES when any element was matched, NO otherwise. +BOOL inlineElementAtTapLocation(ENRMPlatformTextView *textView, ENRMTapRecognizer *recognizer, + NSString *_Nullable *_Nullable outLinkURL, NSString *_Nullable *_Nullable outMentionURL, + NSString *_Nullable *_Nullable outMentionText, + NSString *_Nullable *_Nullable outCitationURL, + NSString *_Nullable *_Nullable outCitationText); + +/// Returns YES if the point (in textView coordinates) is on a link, mention, +/// citation, spoiler, or task list checkbox. BOOL isPointOnInteractiveElement(ENRMPlatformTextView *textView, CGPoint point); #ifdef __cplusplus diff --git a/ios/utils/LinkTapUtils.m b/ios/utils/LinkTapUtils.m index 26ea2d4d..5d0ebd88 100644 --- a/ios/utils/LinkTapUtils.m +++ b/ios/utils/LinkTapUtils.m @@ -1,6 +1,7 @@ #import "LinkTapUtils.h" #import "ENRMSpoilerTapUtils.h" #import "ENRMTextHitTest.h" +#import "LinkRenderer.h" NSString *_Nullable linkURLAtTapLocation(ENRMPlatformTextView *textView, ENRMTapRecognizer *recognizer) { @@ -21,6 +22,47 @@ return [attrText attribute:@"linkURL" atIndex:characterRange.location effectiveRange:NULL]; } +BOOL inlineElementAtTapLocation(ENRMPlatformTextView *textView, ENRMTapRecognizer *recognizer, + NSString *_Nullable *_Nullable outLinkURL, NSString *_Nullable *_Nullable outMentionURL, + NSString *_Nullable *_Nullable outMentionText, + NSString *_Nullable *_Nullable outCitationURL, + NSString *_Nullable *_Nullable outCitationText) +{ + NSUInteger characterIndex = ENRMCharacterIndexForTap(textView, recognizer); + if (characterIndex == NSNotFound) + return NO; + + NSAttributedString *attrText = ENRMGetAttributedText(textView); + NSDictionary *attrs = [attrText attributesAtIndex:characterIndex effectiveRange:NULL]; + + NSString *mentionURL = attrs[ENRMMentionURLAttributeName]; + if (mentionURL) { + if (outMentionURL) + *outMentionURL = mentionURL; + if (outMentionText) + *outMentionText = attrs[ENRMMentionTextAttributeName] ?: @""; + return YES; + } + + NSString *citationURL = attrs[ENRMCitationURLAttributeName]; + if (citationURL) { + if (outCitationURL) + *outCitationURL = citationURL; + if (outCitationText) + *outCitationText = attrs[ENRMCitationTextAttributeName] ?: @""; + return YES; + } + + NSString *linkURL = attrs[@"linkURL"]; + if (linkURL) { + if (outLinkURL) + *outLinkURL = linkURL; + return YES; + } + + return NO; +} + BOOL isPointOnInteractiveElement(ENRMPlatformTextView *textView, CGPoint point) { NSUInteger charIndex = ENRMCharacterIndexAtPoint(textView, point); @@ -28,5 +70,7 @@ BOOL isPointOnInteractiveElement(ENRMPlatformTextView *textView, CGPoint point) return NO; NSDictionary *attrs = [ENRMGetAttributedText(textView) attributesAtIndex:charIndex effectiveRange:NULL]; - return attrs[@"linkURL"] != nil || [attrs[@"TaskItem"] boolValue] || attrs[SpoilerAttributeName] != nil; + return attrs[@"linkURL"] != nil || attrs[ENRMMentionURLAttributeName] != nil || + attrs[ENRMCitationURLAttributeName] != nil || [attrs[@"TaskItem"] boolValue] || + attrs[SpoilerAttributeName] != nil; } diff --git a/ios/utils/MarkdownExtractor.m b/ios/utils/MarkdownExtractor.m index fc1dd0df..e29c4616 100644 --- a/ios/utils/MarkdownExtractor.m +++ b/ios/utils/MarkdownExtractor.m @@ -8,6 +8,7 @@ #import "ENRMMathInlineAttachment.h" #endif #import "LastElementUtils.h" +#import "LinkRenderer.h" #import "ListItemRenderer.h" #import "RuntimeKeys.h" #import "ThematicBreakAttachment.h" @@ -290,7 +291,18 @@ static void extractFontTraits(NSDictionary *attrs, BOOL *isBold, BOOL *isItalic, NSNumber *underlineStyle = attrs[NSUnderlineStyleAttributeName]; BOOL isUnderline = (underlineStyle != nil && [underlineStyle integerValue] != 0); + // Mentions / citations are stored as inline text tagged with custom + // attributes. When the range covers a mention we emit + // `[text](mention://)`; citations likewise become + // `[text](citation://)` so copy/paste roundtrips cleanly. NSString *linkURL = attrs[NSLinkAttributeName]; + NSString *mentionURL = attrs[ENRMMentionURLAttributeName]; + NSString *citationURL = attrs[ENRMCitationURLAttributeName]; + if (mentionURL) { + linkURL = [@"mention://" stringByAppendingString:mentionURL]; + } else if (citationURL) { + linkURL = [@"citation://" stringByAppendingString:citationURL]; + } NSString *segment = applyInlineFormatting(text, isBold, isItalic, isMonospace, isStrikethrough, isUnderline, linkURL); diff --git a/ios/utils/MentionBackground.h b/ios/utils/MentionBackground.h new file mode 100644 index 00000000..8ea931e6 --- /dev/null +++ b/ios/utils/MentionBackground.h @@ -0,0 +1,25 @@ +#pragma once +#import "ENRMUIKit.h" +#import "StyleConfig.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + * Draws the rounded-pill background + optional border behind any glyph range + * tagged with the `ENRMMentionURLAttributeName` attribute. Runs from inside + * `NSLayoutManager.drawBackgroundForGlyphRange:` so mention pills don't + * require an NSTextAttachment — selection, copy/paste, and long-press all + * behave like normal inline text. + */ +@interface MentionBackground : NSObject + +- (instancetype)initWithConfig:(StyleConfig *)config; + +- (void)drawBackgroundsForGlyphRange:(NSRange)glyphsToShow + layoutManager:(NSLayoutManager *)layoutManager + textContainer:(NSTextContainer *)textContainer + atPoint:(CGPoint)origin; + +@end + +NS_ASSUME_NONNULL_END diff --git a/ios/utils/MentionBackground.m b/ios/utils/MentionBackground.m new file mode 100644 index 00000000..a4bb7074 --- /dev/null +++ b/ios/utils/MentionBackground.m @@ -0,0 +1,153 @@ +#import "MentionBackground.h" +#import "ENRMUIKit.h" +#import "LinkRenderer.h" + +@implementation MentionBackground { + StyleConfig *_config; +} + +- (instancetype)initWithConfig:(StyleConfig *)config +{ + self = [super init]; + if (self) { + _config = config; + } + return self; +} + +- (void)drawBackgroundsForGlyphRange:(NSRange)glyphsToShow + layoutManager:(NSLayoutManager *)layoutManager + textContainer:(NSTextContainer *)textContainer + atPoint:(CGPoint)origin +{ + NSTextStorage *textStorage = layoutManager.textStorage; + if (!textStorage || textStorage.length == 0) + return; + + NSRange charRange = [layoutManager characterRangeForGlyphRange:glyphsToShow actualGlyphRange:NULL]; + if (charRange.location == NSNotFound || charRange.length == 0) + return; + + RCTUIColor *bgColor = [_config mentionBackgroundColor]; + RCTUIColor *borderColor = [_config mentionBorderColor]; + CGFloat borderWidth = [_config mentionBorderWidth]; + CGFloat borderRadius = [_config mentionBorderRadius]; + CGFloat paddingH = [_config mentionPaddingHorizontal]; + CGFloat paddingV = [_config mentionPaddingVertical]; + + // Bail early when there is nothing visible to draw. + if (!bgColor && (!borderColor || borderWidth <= 0)) + return; + + NSUInteger totalGlyphs = [layoutManager numberOfGlyphs]; + + [textStorage + enumerateAttribute:ENRMMentionURLAttributeName + inRange:NSMakeRange(0, textStorage.length) + options:0 + usingBlock:^(id value, NSRange range, BOOL *stop) { + if (!value || range.length == 0) + return; + if (NSIntersectionRange(range, charRange).length == 0) + return; + + NSRange glyphRange = [layoutManager glyphRangeForCharacterRange:range actualCharacterRange:NULL]; + if (glyphRange.location == NSNotFound || glyphRange.length == 0) + return; + + // Pick up the font actually applied to the mention glyphs so the + // pill can be sized to the mention font, not to the (possibly + // taller) line height. + UIFont *mentionFont = [textStorage attribute:NSFontAttributeName + atIndex:range.location + effectiveRange:NULL]; + + [layoutManager + enumerateLineFragmentsForGlyphRange:glyphRange + usingBlock:^(CGRect lineRect, CGRect usedRect, NSTextContainer *tc, + NSRange lineRange, BOOL *lineStop) { + NSRange intersect = NSIntersectionRange(lineRange, glyphRange); + if (intersect.length == 0) + return; + + // Horizontal extent: compute from glyph ADVANCE positions + // (not ink bounds) so the pill hugs the glyph run exactly, + // and subtract any trailing kerning we stamped on the + // last character. Using boundingRectForGlyphRange: here + // would include that kerning and let adjacent mention + // pills visually overlap. + NSUInteger firstGlyph = intersect.location; + NSUInteger lastGlyph = NSMaxRange(intersect) - 1; + + CGPoint firstLoc = [layoutManager locationForGlyphAtIndex:firstGlyph]; + CGFloat pillLeftX = lineRect.origin.x + firstLoc.x; + + CGFloat pillRightX; + NSUInteger afterLastGlyph = NSMaxRange(intersect); + BOOL canQueryNext = (afterLastGlyph < totalGlyphs) && + (afterLastGlyph < NSMaxRange(lineRange)); + if (canQueryNext) { + CGPoint nextLoc = + [layoutManager locationForGlyphAtIndex:afterLastGlyph]; + pillRightX = lineRect.origin.x + nextLoc.x; + + // Subtract the trailing NSKern (if any) so the pill + // ends exactly at the last glyph's natural advance, + // not inside the kerning gap used to space chips. + NSUInteger lastCharIndex = + [layoutManager characterIndexForGlyphAtIndex:lastGlyph]; + if (lastCharIndex < textStorage.length) { + NSNumber *kern = [textStorage attribute:NSKernAttributeName + atIndex:lastCharIndex + effectiveRange:NULL]; + if (kern) { + pillRightX -= [kern doubleValue]; + } + } + } else { + // End of line or end of buffer: fall back to the last + // glyph's ink bounding rect (trailing kerning is + // irrelevant when nothing follows it on the line). + CGRect lastRect = + [layoutManager boundingRectForGlyphRange:NSMakeRange(lastGlyph, 1) + inTextContainer:textContainer]; + pillRightX = lastRect.origin.x + lastRect.size.width; + } + + // Vertical extent: derive from the mention glyphs' own + // baseline + font metrics so the pill hugs the mention + // text rather than stretching to the full line height. + CGFloat baselineY = lineRect.origin.y + firstLoc.y; + + CGFloat ascent = mentionFont ? mentionFont.ascender : 0; + // UIFont.descender is negative; subtract to move down. + CGFloat descent = mentionFont ? mentionFont.descender : 0; + + CGFloat pillTop = baselineY - ascent - paddingV; + CGFloat pillBottom = baselineY - descent + paddingV; + + CGRect pillRect = + CGRectMake(pillLeftX + origin.x - paddingH, pillTop + origin.y, + MAX(0, (pillRightX - pillLeftX)) + paddingH * 2, + MAX(0, pillBottom - pillTop)); + + CGFloat radius = MIN( + borderRadius, MIN(pillRect.size.width, pillRect.size.height) / 2.0); + UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:pillRect + cornerRadius:radius]; + + if (bgColor) { + [bgColor setFill]; + [path fill]; + } + + if (borderColor && borderWidth > 0) { + path.lineWidth = borderWidth; + [borderColor setStroke]; + [path stroke]; + } + }]; + }]; +} + +@end diff --git a/ios/utils/PasteboardUtils.m b/ios/utils/PasteboardUtils.m index c89ce549..7a674c51 100644 --- a/ios/utils/PasteboardUtils.m +++ b/ios/utils/PasteboardUtils.m @@ -1,6 +1,7 @@ #import "PasteboardUtils.h" #import "ENRMImageAttachment.h" #import "HTMLGenerator.h" +#import "LinkRenderer.h" #import "MarkdownExtractor.h" #import "RTFExportUtils.h" #import "StyleConfig.h" @@ -53,6 +54,71 @@ static void addHTMLData(NSMutableDictionary *items, NSAttributedString *attribut } } +/** + * Returns a copy of the attributed string with any character ranges tagged by + * `ENRMCitationURLAttributeName` removed entirely. Citations are reference + * metadata, not prose — stripping them here keeps every export flavor + * (plain, HTML, RTF, RTFD, markdown) consistently citation-free, so pasting + * into a rich-text destination like Notes or Mail no longer surfaces the + * citation marker. + */ +static NSAttributedString *attributedStringWithoutCitations(NSAttributedString *attributedString) +{ + NSRange fullRange = NSMakeRange(0, attributedString.length); + NSMutableArray *rangesToRemove = [NSMutableArray array]; + + [attributedString enumerateAttribute:ENRMCitationURLAttributeName + inRange:fullRange + options:0 + usingBlock:^(id value, NSRange range, BOOL *stop) { + if (!value || range.length == 0) + return; + [rangesToRemove addObject:[NSValue valueWithRange:range]]; + }]; + + if (rangesToRemove.count == 0) + return attributedString; + + NSMutableAttributedString *mutable = [attributedString mutableCopy]; + // Delete in reverse so earlier ranges remain valid after the edits. + for (NSInteger i = (NSInteger)rangesToRemove.count - 1; i >= 0; i--) { + NSRange range = [rangesToRemove[i] rangeValue]; + if (NSMaxRange(range) <= mutable.length) { + [mutable deleteCharactersInRange:range]; + } + } + return mutable; +} + +/** + * Strips `[text](citation://...)` occurrences from a pre-extracted markdown + * string so the markdown pasteboard flavor stays consistent with the other + * flavors in the default Copy action. + */ +static NSString *markdownWithoutCitations(NSString *markdown) +{ + if (markdown.length == 0) + return markdown; + + static NSRegularExpression *regex = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + // Matches a standard CommonMark link where the URL begins with `citation://`. + // The label body uses `[^\]]*` so it stops at the first `]` — nested + // brackets in citation labels aren't a supported case in our emitter. + regex = [NSRegularExpression regularExpressionWithPattern:@"\\[[^\\]]*\\]\\(citation://[^\\)]*\\)" + options:0 + error:NULL]; + }); + + if (!regex) + return markdown; + return [regex stringByReplacingMatchesInString:markdown + options:0 + range:NSMakeRange(0, markdown.length) + withTemplate:@""]; +} + #pragma mark - Public API void copyStringToPasteboard(NSString *string) @@ -90,20 +156,29 @@ void copyAttributedStringToPasteboard(NSAttributedString *attributedString, NSSt if (!attributedString || attributedString.length == 0) return; + // Elide citations before deriving any export flavor so rich-text + // destinations (Notes, Mail, Pages, contenteditable, etc.) don't end up + // with the reference marker when the user pastes. The dedicated + // "Copy as Markdown" action still preserves citations for round-tripping. + NSAttributedString *cleaned = attributedStringWithoutCitations(attributedString); + if (cleaned.length == 0) + return; + NSMutableDictionary *items = [NSMutableDictionary dictionary]; - items[kUTIPlainText] = attributedString.string; + items[kUTIPlainText] = cleaned.string; - if (markdown.length > 0) { - items[kUTIMarkdown] = markdown; + NSString *cleanedMarkdown = markdownWithoutCitations(markdown); + if (cleanedMarkdown.length > 0) { + items[kUTIMarkdown] = cleanedMarkdown; } if (styleConfig) { - addHTMLData(items, attributedString, styleConfig); + addHTMLData(items, cleaned, styleConfig); } // RTF export requires preprocessing (backgrounds, markers, normalized spacing) - NSAttributedString *rtfPrepared = prepareAttributedStringForRTFExport(attributedString, styleConfig); + NSAttributedString *rtfPrepared = prepareAttributedStringForRTFExport(cleaned, styleConfig); NSRange rtfRange = NSMakeRange(0, rtfPrepared.length); addRTFDData(items, rtfPrepared, rtfRange); diff --git a/ios/utils/RuntimeKeys.h b/ios/utils/RuntimeKeys.h index 5e1bef5e..182b8d46 100644 --- a/ios/utils/RuntimeKeys.h +++ b/ios/utils/RuntimeKeys.h @@ -32,6 +32,14 @@ extern void *kListMarkerDrawerKey; // Used by TextViewLayoutManager for code block background drawing extern void *kCodeBlockBackgroundKey; +// Key for storing MentionBackground instance on NSLayoutManager +// Used by TextViewLayoutManager for inline mention pill drawing +extern void *kMentionBackgroundKey; + +// Key for storing CitationBackground instance on NSLayoutManager +// Used by TextViewLayoutManager for inline citation chip drawing +extern void *kCitationBackgroundKey; + // Custom attribute keys for markdown type tracking (used for Copy Markdown) extern NSString *const MarkdownTypeAttributeName; diff --git a/ios/utils/RuntimeKeys.m b/ios/utils/RuntimeKeys.m index 02ae3e90..e2030f73 100644 --- a/ios/utils/RuntimeKeys.m +++ b/ios/utils/RuntimeKeys.m @@ -6,6 +6,8 @@ void *kBlockquoteBorderKey = &kBlockquoteBorderKey; void *kListMarkerDrawerKey = &kListMarkerDrawerKey; void *kCodeBlockBackgroundKey = &kCodeBlockBackgroundKey; +void *kMentionBackgroundKey = &kMentionBackgroundKey; +void *kCitationBackgroundKey = &kCitationBackgroundKey; // Custom attribute for markdown type tracking NSString *const MarkdownTypeAttributeName = @"MarkdownType"; diff --git a/ios/utils/StylePropsUtils.h b/ios/utils/StylePropsUtils.h index cbf73cad..52528225 100644 --- a/ios/utils/StylePropsUtils.h +++ b/ios/utils/StylePropsUtils.h @@ -1069,5 +1069,161 @@ BOOL applyMarkdownStyleToConfig(StyleConfig *config, const MarkdownStyle &newSty changed = YES; } + // ── Mention ───────────────────────────────────────────────────────────── + + if (newStyle.mention.color != oldStyle.mention.color) { + if (newStyle.mention.color) { + [config setMentionColor:RCTUIColorFromSharedColor(newStyle.mention.color)]; + } else { + [config setMentionColor:nullptr]; + } + changed = YES; + } + + if (newStyle.mention.backgroundColor != oldStyle.mention.backgroundColor) { + if (newStyle.mention.backgroundColor) { + [config setMentionBackgroundColor:RCTUIColorFromSharedColor(newStyle.mention.backgroundColor)]; + } else { + [config setMentionBackgroundColor:nullptr]; + } + changed = YES; + } + + if (newStyle.mention.borderColor != oldStyle.mention.borderColor) { + if (newStyle.mention.borderColor) { + [config setMentionBorderColor:RCTUIColorFromSharedColor(newStyle.mention.borderColor)]; + } else { + [config setMentionBorderColor:nullptr]; + } + changed = YES; + } + + if (newStyle.mention.borderWidth != oldStyle.mention.borderWidth) { + [config setMentionBorderWidth:newStyle.mention.borderWidth]; + changed = YES; + } + + if (newStyle.mention.borderRadius != oldStyle.mention.borderRadius) { + [config setMentionBorderRadius:newStyle.mention.borderRadius]; + changed = YES; + } + + if (newStyle.mention.paddingHorizontal != oldStyle.mention.paddingHorizontal) { + [config setMentionPaddingHorizontal:newStyle.mention.paddingHorizontal]; + changed = YES; + } + + if (newStyle.mention.paddingVertical != oldStyle.mention.paddingVertical) { + [config setMentionPaddingVertical:newStyle.mention.paddingVertical]; + changed = YES; + } + + if (newStyle.mention.fontFamily != oldStyle.mention.fontFamily) { + if (!newStyle.mention.fontFamily.empty()) { + NSString *fontFamily = [[NSString alloc] initWithUTF8String:newStyle.mention.fontFamily.c_str()]; + [config setMentionFontFamily:fontFamily]; + } else { + [config setMentionFontFamily:nullptr]; + } + changed = YES; + } + + if (newStyle.mention.fontWeight != oldStyle.mention.fontWeight) { + if (!newStyle.mention.fontWeight.empty()) { + NSString *fontWeight = [[NSString alloc] initWithUTF8String:newStyle.mention.fontWeight.c_str()]; + [config setMentionFontWeight:fontWeight]; + } else { + [config setMentionFontWeight:nullptr]; + } + changed = YES; + } + + if (newStyle.mention.fontSize != oldStyle.mention.fontSize) { + [config setMentionFontSize:newStyle.mention.fontSize]; + changed = YES; + } + + if (newStyle.mention.pressedOpacity != oldStyle.mention.pressedOpacity) { + [config setMentionPressedOpacity:newStyle.mention.pressedOpacity]; + changed = YES; + } + + // ── Citation ──────────────────────────────────────────────────────────── + + if (newStyle.citation.color != oldStyle.citation.color) { + if (newStyle.citation.color) { + [config setCitationColor:RCTUIColorFromSharedColor(newStyle.citation.color)]; + } else { + [config setCitationColor:nullptr]; + } + changed = YES; + } + + if (newStyle.citation.fontSizeMultiplier != oldStyle.citation.fontSizeMultiplier) { + [config setCitationFontSizeMultiplier:newStyle.citation.fontSizeMultiplier]; + changed = YES; + } + + if (newStyle.citation.baselineOffsetPx != oldStyle.citation.baselineOffsetPx) { + [config setCitationBaselineOffsetPx:newStyle.citation.baselineOffsetPx]; + changed = YES; + } + + if (newStyle.citation.fontWeight != oldStyle.citation.fontWeight) { + if (!newStyle.citation.fontWeight.empty()) { + NSString *fontWeight = [[NSString alloc] initWithUTF8String:newStyle.citation.fontWeight.c_str()]; + [config setCitationFontWeight:fontWeight]; + } else { + [config setCitationFontWeight:nullptr]; + } + changed = YES; + } + + { + BOOL newUnderline = newStyle.citation.underline ? YES : NO; + if (newStyle.citation.underline != oldStyle.citation.underline || [config citationUnderline] != newUnderline) { + [config setCitationUnderline:newUnderline]; + changed = YES; + } + } + + if (newStyle.citation.backgroundColor != oldStyle.citation.backgroundColor) { + if (newStyle.citation.backgroundColor) { + [config setCitationBackgroundColor:RCTUIColorFromSharedColor(newStyle.citation.backgroundColor)]; + } else { + [config setCitationBackgroundColor:nullptr]; + } + changed = YES; + } + + if (newStyle.citation.paddingHorizontal != oldStyle.citation.paddingHorizontal) { + [config setCitationPaddingHorizontal:newStyle.citation.paddingHorizontal]; + changed = YES; + } + + if (newStyle.citation.paddingVertical != oldStyle.citation.paddingVertical) { + [config setCitationPaddingVertical:newStyle.citation.paddingVertical]; + changed = YES; + } + + if (newStyle.citation.borderColor != oldStyle.citation.borderColor) { + if (newStyle.citation.borderColor) { + [config setCitationBorderColor:RCTUIColorFromSharedColor(newStyle.citation.borderColor)]; + } else { + [config setCitationBorderColor:nullptr]; + } + changed = YES; + } + + if (newStyle.citation.borderWidth != oldStyle.citation.borderWidth) { + [config setCitationBorderWidth:newStyle.citation.borderWidth]; + changed = YES; + } + + if (newStyle.citation.borderRadius != oldStyle.citation.borderRadius) { + [config setCitationBorderRadius:newStyle.citation.borderRadius]; + changed = YES; + } + return changed; } diff --git a/ios/utils/TextViewLayoutManager.mm b/ios/utils/TextViewLayoutManager.mm index dca3717b..4bf11b4a 100644 --- a/ios/utils/TextViewLayoutManager.mm +++ b/ios/utils/TextViewLayoutManager.mm @@ -1,8 +1,10 @@ #import "TextViewLayoutManager.h" #import "BlockquoteBorder.h" +#import "CitationBackground.h" #import "CodeBackground.h" #import "CodeBlockBackground.h" #import "ListMarkerDrawer.h" +#import "MentionBackground.h" #import "RuntimeKeys.h" #import "StyleConfig.h" #import @@ -42,6 +44,12 @@ - (void)drawBackgroundForGlyphRange:(NSRange)glyphsToShow atPoint:(CGPoint)origi ListMarkerDrawer *markerDrawer = [self getListMarkerDrawerWithConfig:config]; [markerDrawer drawMarkersForGlyphRange:glyphsToShow layoutManager:self textContainer:textContainer atPoint:origin]; + + MentionBackground *mentionBg = [self getMentionBackgroundWithConfig:config]; + [mentionBg drawBackgroundsForGlyphRange:glyphsToShow layoutManager:self textContainer:textContainer atPoint:origin]; + + CitationBackground *citationBg = [self getCitationBackgroundWithConfig:config]; + [citationBg drawBackgroundsForGlyphRange:glyphsToShow layoutManager:self textContainer:textContainer atPoint:origin]; } #pragma mark - Safe Property Accessors @@ -89,6 +97,26 @@ - (CodeBlockBackground *)getCodeBlockBackgroundWithConfig:(StyleConfig *)config return obj; } +- (MentionBackground *)getMentionBackgroundWithConfig:(StyleConfig *)config +{ + MentionBackground *obj = objc_getAssociatedObject(self, kMentionBackgroundKey); + if (!obj) { + obj = [[MentionBackground alloc] initWithConfig:config]; + objc_setAssociatedObject(self, kMentionBackgroundKey, obj, OBJC_ASSOCIATION_RETAIN_NONATOMIC); + } + return obj; +} + +- (CitationBackground *)getCitationBackgroundWithConfig:(StyleConfig *)config +{ + CitationBackground *obj = objc_getAssociatedObject(self, kCitationBackgroundKey); + if (!obj) { + obj = [[CitationBackground alloc] initWithConfig:config]; + objc_setAssociatedObject(self, kCitationBackgroundKey, obj, OBJC_ASSOCIATION_RETAIN_NONATOMIC); + } + return obj; +} + #pragma mark - Configuration - (StyleConfig *)config @@ -103,6 +131,8 @@ - (void)setConfig:(StyleConfig *)config objc_setAssociatedObject(self, kCodeBlockBackgroundKey, nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC); objc_setAssociatedObject(self, kBlockquoteBorderKey, nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC); objc_setAssociatedObject(self, kListMarkerDrawerKey, nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC); + objc_setAssociatedObject(self, kMentionBackgroundKey, nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC); + objc_setAssociatedObject(self, kCitationBackgroundKey, nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC); objc_setAssociatedObject(self, kStyleConfigKey, config, OBJC_ASSOCIATION_RETAIN_NONATOMIC); diff --git a/ios/views/TableContainerView.h b/ios/views/TableContainerView.h index b444236b..00d1d35f 100644 --- a/ios/views/TableContainerView.h +++ b/ios/views/TableContainerView.h @@ -7,6 +7,8 @@ NS_ASSUME_NONNULL_BEGIN typedef void (^TableLinkPressBlock)(NSString *url); +typedef void (^TableMentionPressBlock)(NSString *url, NSString *text); +typedef void (^TableCitationPressBlock)(NSString *url, NSString *text); @interface TableContainerView : RCTUIView @@ -23,6 +25,8 @@ typedef void (^TableLinkPressBlock)(NSString *url); @property (nonatomic, copy, nullable) TableLinkPressBlock onLinkPress; @property (nonatomic, copy, nullable) TableLinkPressBlock onLinkLongPress; +@property (nonatomic, copy, nullable) TableMentionPressBlock onMentionPress; +@property (nonatomic, copy, nullable) TableCitationPressBlock onCitationPress; @property (nonatomic, assign) BOOL enableLinkPreview; diff --git a/ios/views/TableContainerView.m b/ios/views/TableContainerView.m index d538e5e0..47091ced 100644 --- a/ios/views/TableContainerView.m +++ b/ios/views/TableContainerView.m @@ -409,9 +409,21 @@ - (UITextView *)createCellTextView - (void)cellTextTapped:(UITapGestureRecognizer *)recognizer { UITextView *textView = (UITextView *)recognizer.view; - NSString *url = linkURLAtTapLocation(textView, recognizer); - if (url && self.onLinkPress) - self.onLinkPress(url); + NSString *linkURL = nil; + NSString *mentionURL = nil; + NSString *mentionText = nil; + NSString *citationURL = nil; + NSString *citationText = nil; + if (inlineElementAtTapLocation(textView, recognizer, &linkURL, &mentionURL, &mentionText, &citationURL, + &citationText)) { + if (mentionURL && self.onMentionPress) { + self.onMentionPress(mentionURL, mentionText ?: @""); + } else if (citationURL && self.onCitationPress) { + self.onCitationPress(citationURL, citationText ?: @""); + } else if (linkURL && self.onLinkPress) { + self.onLinkPress(linkURL); + } + } } - (BOOL)textView:(UITextView *)textView diff --git a/lib/module/EnrichedMarkdownNativeComponent.ts b/lib/module/EnrichedMarkdownNativeComponent.ts new file mode 100644 index 00000000..92190aab --- /dev/null +++ b/lib/module/EnrichedMarkdownNativeComponent.ts @@ -0,0 +1,393 @@ +import { + codegenNativeComponent, + type ViewProps, + type CodegenTypes, + type ColorValue, +} from 'react-native'; + +// All block styles extend this interface +interface BaseBlockStyleInternal { + fontSize: CodegenTypes.Float; + fontFamily: string; + fontWeight: string; + color: ColorValue; + marginTop: CodegenTypes.Float; + marginBottom: CodegenTypes.Float; + lineHeight: CodegenTypes.Float; +} + +interface ParagraphStyleInternal extends BaseBlockStyleInternal { + textAlign: string; +} + +interface HeadingStyleInternal extends BaseBlockStyleInternal { + textAlign: string; +} + +interface BlockquoteStyleInternal extends BaseBlockStyleInternal { + borderColor: ColorValue; + borderWidth: CodegenTypes.Float; + gapWidth: CodegenTypes.Float; + backgroundColor: ColorValue; +} + +interface ListStyleInternal extends BaseBlockStyleInternal { + bulletColor: ColorValue; + bulletSize: CodegenTypes.Float; + markerMinWidth: CodegenTypes.Float; + markerColor: ColorValue; + markerFontWeight: string; + gapWidth: CodegenTypes.Float; + marginLeft: CodegenTypes.Float; +} + +interface CodeBlockStyleInternal extends BaseBlockStyleInternal { + backgroundColor: ColorValue; + borderColor: ColorValue; + borderRadius: CodegenTypes.Float; + borderWidth: CodegenTypes.Float; + padding: CodegenTypes.Float; +} + +interface LinkStyleInternal { + fontFamily: string; + color: ColorValue; + underline: boolean; +} + +interface StrongStyleInternal { + fontFamily: string; + fontWeight: string; + color?: ColorValue; +} + +interface EmphasisStyleInternal { + fontFamily: string; + fontStyle: string; + color?: ColorValue; +} + +interface StrikethroughStyleInternal { + color: ColorValue; +} + +interface UnderlineStyleInternal { + color: ColorValue; +} + +interface CodeStyleInternal { + fontFamily: string; + fontSize: CodegenTypes.Float; + color: ColorValue; + backgroundColor: ColorValue; + borderColor: ColorValue; +} + +interface ImageStyleInternal { + height: CodegenTypes.Float; + borderRadius: CodegenTypes.Float; + marginTop: CodegenTypes.Float; + marginBottom: CodegenTypes.Float; +} + +interface InlineImageStyleInternal { + size: CodegenTypes.Float; +} + +interface ThematicBreakStyleInternal { + color: ColorValue; + height: CodegenTypes.Float; + marginTop: CodegenTypes.Float; + marginBottom: CodegenTypes.Float; +} + +interface TableStyleInternal extends BaseBlockStyleInternal { + headerFontFamily: string; + headerBackgroundColor: ColorValue; + headerTextColor: ColorValue; + rowEvenBackgroundColor: ColorValue; + rowOddBackgroundColor: ColorValue; + borderColor: ColorValue; + borderWidth: CodegenTypes.Float; + borderRadius: CodegenTypes.Float; + cellPaddingHorizontal: CodegenTypes.Float; + cellPaddingVertical: CodegenTypes.Float; +} + +interface TaskListStyleInternal { + checkedColor: ColorValue; + borderColor: ColorValue; + checkboxSize: CodegenTypes.Float; + checkboxBorderRadius: CodegenTypes.Float; + checkmarkColor: ColorValue; + checkedTextColor: ColorValue; + checkedStrikethrough: boolean; +} + +interface MathStyleInternal { + fontSize: CodegenTypes.Float; + color: ColorValue; + backgroundColor: ColorValue; + padding: CodegenTypes.Float; + marginTop: CodegenTypes.Float; + marginBottom: CodegenTypes.Float; + textAlign: string; +} + +interface InlineMathStyleInternal { + color: ColorValue; +} + +interface SpoilerParticlesStyleInternal { + density: CodegenTypes.Float; + speed: CodegenTypes.Float; +} + +interface SpoilerSolidStyleInternal { + borderRadius: CodegenTypes.Float; +} + +interface SpoilerStyleInternal { + color: ColorValue; + particles: SpoilerParticlesStyleInternal; + solid: SpoilerSolidStyleInternal; +} + +interface MentionStyleInternal { + color: ColorValue; + backgroundColor: ColorValue; + borderColor: ColorValue; + borderWidth: CodegenTypes.Float; + borderRadius: CodegenTypes.Float; + paddingHorizontal: CodegenTypes.Float; + paddingVertical: CodegenTypes.Float; + fontFamily: string; + fontWeight: string; + fontSize: CodegenTypes.Float; + pressedOpacity: CodegenTypes.Float; +} + +interface CitationStyleInternal { + color: ColorValue; + fontSizeMultiplier: CodegenTypes.Float; + baselineOffsetPx: CodegenTypes.Float; + fontWeight: string; + underline: boolean; + backgroundColor: ColorValue; + paddingHorizontal: CodegenTypes.Float; + paddingVertical: CodegenTypes.Float; + borderColor: ColorValue; + borderWidth: CodegenTypes.Float; + borderRadius: CodegenTypes.Float; +} + +export interface MarkdownStyleInternal { + paragraph: ParagraphStyleInternal; + h1: HeadingStyleInternal; + h2: HeadingStyleInternal; + h3: HeadingStyleInternal; + h4: HeadingStyleInternal; + h5: HeadingStyleInternal; + h6: HeadingStyleInternal; + blockquote: BlockquoteStyleInternal; + list: ListStyleInternal; + codeBlock: CodeBlockStyleInternal; + link: LinkStyleInternal; + strong: StrongStyleInternal; + em: EmphasisStyleInternal; + strikethrough: StrikethroughStyleInternal; + underline: UnderlineStyleInternal; + code: CodeStyleInternal; + image: ImageStyleInternal; + inlineImage: InlineImageStyleInternal; + thematicBreak: ThematicBreakStyleInternal; + table: TableStyleInternal; + taskList: TaskListStyleInternal; + math: MathStyleInternal; + inlineMath: InlineMathStyleInternal; + spoiler: SpoilerStyleInternal; + mention: MentionStyleInternal; + citation: CitationStyleInternal; +} + +export interface LinkPressEvent { + url: string; +} + +export interface LinkLongPressEvent { + url: string; +} + +export interface MentionPressEvent { + url: string; + text: string; +} + +export interface CitationPressEvent { + url: string; + text: string; +} + +export interface TaskListItemPressEvent { + index: CodegenTypes.Int32; + checked: boolean; + text: string; +} + +export interface ContextMenuItemConfig { + text: string; + icon?: string; +} + +export interface OnContextMenuItemPressEvent { + itemText: string; + selectedText: string; + selectionStart: CodegenTypes.Int32; + selectionEnd: CodegenTypes.Int32; +} + +/** + * MD4C parser flags configuration. + * Controls how the markdown parser interprets certain syntax. + */ +export interface Md4cFlagsInternal { + /** + * Enable underline syntax support (__text__). + * When enabled, underscores are treated as underline markers. + * When disabled, underscores are treated as emphasis markers (same as asterisks). + * @default false + */ + underline: boolean; + /** + * Enable LaTeX math span parsing ($..$ and $$..$$). + * When disabled, dollar signs are treated as plain text. + * @default true + */ + latexMath: boolean; +} + +export interface NativeProps extends ViewProps { + /** + * Markdown content to render. + */ + markdown: string; + /** + * Internal style configuration for markdown elements. + * Always provided with complete defaults via normalizeMarkdownStyle. + * Block styles (paragraph, headings) contain fontSize, fontFamily, fontWeight, and color. + */ + markdownStyle: MarkdownStyleInternal; + /** + * Callback fired when a link is pressed. + * Receives the URL that was tapped. + */ + onLinkPress?: CodegenTypes.BubblingEventHandler; + /** + * Callback fired when a link is long pressed. + * Receives the URL that was long pressed. + * - iOS: When provided, overrides the system link preview behavior. + * - Android: Handles long press gestures on links. + */ + onLinkLongPress?: CodegenTypes.BubblingEventHandler; + /** + * Callback fired when a task list checkbox is tapped. + * Receives the 0-based task index, current checked state, and the item's plain text. + */ + onTaskListItemPress?: CodegenTypes.BubblingEventHandler; + /** + * Callback fired when an inline mention pill (`mention://`) is pressed. + */ + onMentionPress?: CodegenTypes.BubblingEventHandler; + /** + * Callback fired when an inline citation (`citation://`) is pressed. + */ + onCitationPress?: CodegenTypes.BubblingEventHandler; + /** + * Controls whether the system link preview is shown on long press (iOS only). + * + * When `true` (default), long-pressing a link shows the native iOS link preview. + * When `false`, the system preview is suppressed. + * + * Automatically set to `false` when `onLinkLongPress` is provided (unless explicitly overridden). + * + * Android: No-op (Android doesn't have a system link preview). + * + * @default true + */ + enableLinkPreview?: CodegenTypes.WithDefault; + /** + * - iOS: Controls text selection and link previews on long press. + * - Android: Controls text selection. + * @default true + */ + selectable?: boolean; + /** + * Color of the text selection highlight. + * + * On iOS, this also affects the caret and selection handle colors + * (they share a single tint). + * + * @platform ios, android, web + */ + selectionColor?: ColorValue; + /** + * Color of the selection handles (drag anchors). + * No-op on API levels below 29. + * + * @platform android + */ + selectionHandleColor?: ColorValue; + /** + * MD4C parser flags configuration. + * Controls how the markdown parser interprets certain syntax. + */ + md4cFlags: Md4cFlagsInternal; + /** + * Specifies whether fonts should scale to respect Text Size accessibility settings. + * When false, text will not scale with the user's accessibility settings. + * @default true + */ + allowFontScaling?: CodegenTypes.WithDefault; + /** + * Specifies the largest possible scale a font can reach when allowFontScaling is enabled. + * Possible values: + * - undefined/null (default): inherit from parent or global default (no limit) + * - 0: no limit, ignore parent/global default + * - >= 1: sets the maxFontSizeMultiplier of this node to this value + * @default undefined + */ + maxFontSizeMultiplier?: CodegenTypes.Float; + /** + * When false (default), removes trailing margin from the last element to eliminate bottom spacing. + * When true, keeps the trailing margin from the last element's marginBottom style. + * @default false + */ + allowTrailingMargin?: CodegenTypes.WithDefault; + /** + * When true, newly appended content fades in during streaming updates. + * Only the tail (new characters beyond the previous content) is animated. + * @default false + */ + streamingAnimation?: CodegenTypes.WithDefault; + /** + * Controls how spoiler text is displayed before being revealed. + * - 'particles' (default): animated particle overlay. + * - 'solid': opaque rectangle covering the text. + * @default 'particles' + */ + spoilerOverlay?: CodegenTypes.WithDefault; + + /** + * Custom items to show in the text selection context menu. + */ + contextMenuItems?: ReadonlyArray>; + /** + * Fired when a custom context menu item is pressed. + * Receives the item label, the currently selected text, and the selection range. + */ + onContextMenuItemPress?: CodegenTypes.BubblingEventHandler; +} + +export default codegenNativeComponent('EnrichedMarkdown', { + interfaceOnly: true, +}); diff --git a/lib/module/EnrichedMarkdownTextInput.js b/lib/module/EnrichedMarkdownTextInput.js new file mode 100644 index 00000000..4b01cfc8 --- /dev/null +++ b/lib/module/EnrichedMarkdownTextInput.js @@ -0,0 +1,258 @@ +"use strict"; + +import { useCallback, useEffect, useImperativeHandle, useMemo, useRef } from 'react'; +import EnrichedMarkdownTextInputNativeComponent, { Commands } from './EnrichedMarkdownTextInputNativeComponent'; +import { normalizeMarkdownTextInputStyle } from "./normalizeMarkdownTextInputStyle.js"; +import { toNativeRegexConfig } from "./utils/regexParser.js"; +import { jsx as _jsx } from "react/jsx-runtime"; +function getNativeRef(ref) { + if (ref.current == null) { + throw new Error('EnrichedMarkdownTextInput: native ref is not attached. Ensure the component is mounted.'); + } + return ref.current; +} +export const EnrichedMarkdownTextInput = ({ + ref, + markdownStyle, + style, + defaultValue, + placeholder, + placeholderTextColor, + editable = true, + autoFocus = false, + scrollEnabled = true, + autoCapitalize = 'sentences', + multiline = true, + cursorColor, + selectionColor, + onChangeText, + onChangeMarkdown, + onChangeSelection, + onChangeState, + onCaretRectChange, + onLinkDetected, + onFocus, + onBlur, + contextMenuItems, + linkRegex: _linkRegex +}) => { + const nativeRef = useRef(null); + const nextRequestId = useRef(1); + const pendingRequests = useRef(new Map()); + const pendingCaretRectRequests = useRef(new Map()); + const contextMenuCallbacksRef = useRef(new Map()); + useEffect(() => { + const callbacksMap = new Map(); + if (contextMenuItems) { + for (const item of contextMenuItems) { + callbacksMap.set(item.text, item.onPress); + } + } + contextMenuCallbacksRef.current = callbacksMap; + }, [contextMenuItems]); + const nativeContextMenuItems = useMemo(() => contextMenuItems?.filter(item => item.visible !== false).map(item => ({ + text: item.text, + icon: item.icon + })), [contextMenuItems]); + useEffect(() => { + const pending = pendingRequests.current; + const pendingCaretRect = pendingCaretRectRequests.current; + return () => { + const err = new Error('Component unmounted'); + pending.forEach(({ + reject + }) => reject(err)); + pending.clear(); + pendingCaretRect.forEach(({ + reject + }) => reject(err)); + pendingCaretRect.clear(); + }; + }, []); + const normalizedStyle = normalizeMarkdownTextInputStyle(markdownStyle); + const linkRegex = useMemo(() => toNativeRegexConfig(_linkRegex), [_linkRegex]); + const handleLinkDetected = useCallback(e => { + const { + text, + url, + start, + end + } = e.nativeEvent; + onLinkDetected?.({ + text, + url, + start, + end + }); + }, [onLinkDetected]); + const handleChangeText = useCallback(e => { + onChangeText?.(e.nativeEvent.value); + }, [onChangeText]); + const handleChangeMarkdown = useCallback(e => { + onChangeMarkdown?.(e.nativeEvent.value); + }, [onChangeMarkdown]); + const handleChangeSelection = useCallback(e => { + const { + start, + end + } = e.nativeEvent; + onChangeSelection?.({ + start, + end + }); + }, [onChangeSelection]); + const handleChangeState = useCallback(e => { + const { + bold, + italic, + underline, + strikethrough, + spoiler, + link + } = e.nativeEvent; + onChangeState?.({ + bold, + italic, + underline, + strikethrough, + spoiler, + link + }); + }, [onChangeState]); + const handleCaretRectChange = useCallback(e => { + const { + x, + y, + width, + height + } = e.nativeEvent; + onCaretRectChange?.({ + x, + y, + width, + height + }); + }, [onCaretRectChange]); + const handleFocus = useCallback(() => { + onFocus?.(); + }, [onFocus]); + const handleBlur = useCallback(() => { + onBlur?.(); + }, [onBlur]); + const handleRequestMarkdownResult = useCallback(e => { + const { + requestId, + markdown + } = e.nativeEvent; + const pending = pendingRequests.current.get(requestId); + if (!pending) return; + pending.resolve(markdown); + pendingRequests.current.delete(requestId); + }, []); + const handleRequestCaretRectResult = useCallback(e => { + const { + requestId, + x, + y, + width, + height + } = e.nativeEvent; + const pending = pendingCaretRectRequests.current.get(requestId); + if (!pending) return; + pending.resolve({ + x, + y, + width, + height + }); + pendingCaretRectRequests.current.delete(requestId); + }, []); + const handleContextMenuItemPress = useCallback(e => { + const { + itemText, + selectedText, + selectionStart, + selectionEnd, + styleState + } = e.nativeEvent; + const callback = contextMenuCallbacksRef.current.get(itemText); + callback?.({ + text: selectedText, + selection: { + start: selectionStart, + end: selectionEnd + }, + styleState + }); + }, []); + useImperativeHandle(ref, () => { + const node = getNativeRef(nativeRef); + // Codegen's ViewRef resolves to `never` with RN 0.84's function-based + // HostComponent type — the cast is safe at runtime. + const commandRef = node; + return { + measure: callback => node.measure(callback), + measureInWindow: callback => node.measureInWindow(callback), + measureLayout: (relativeToNativeNode, onSuccess, onFail) => node.measureLayout(relativeToNativeNode, onSuccess, onFail), + focus: () => Commands.focus(commandRef), + blur: () => Commands.blur(commandRef), + setValue: markdown => Commands.setValue(commandRef, markdown), + setSelection: (start, end) => Commands.setSelection(commandRef, start, end), + toggleBold: () => Commands.toggleBold(commandRef), + toggleItalic: () => Commands.toggleItalic(commandRef), + toggleUnderline: () => Commands.toggleUnderline(commandRef), + toggleStrikethrough: () => Commands.toggleStrikethrough(commandRef), + toggleSpoiler: () => Commands.toggleSpoiler(commandRef), + setLink: url => Commands.setLink(commandRef, url), + insertLink: (text, url) => Commands.insertLink(commandRef, text, url), + removeLink: () => Commands.removeLink(commandRef), + getMarkdown: () => new Promise((resolve, reject) => { + const requestId = nextRequestId.current++; + pendingRequests.current.set(requestId, { + resolve, + reject + }); + Commands.requestMarkdown(commandRef, requestId); + }), + getCaretRect: () => new Promise((resolve, reject) => { + const requestId = nextRequestId.current++; + pendingCaretRectRequests.current.set(requestId, { + resolve, + reject + }); + Commands.requestCaretRect(commandRef, requestId); + }) + }; + }); + return /*#__PURE__*/_jsx(EnrichedMarkdownTextInputNativeComponent, { + ref: nativeRef, + style: style, + markdownStyle: normalizedStyle, + defaultValue: defaultValue, + placeholder: placeholder, + placeholderTextColor: placeholderTextColor, + editable: editable, + autoFocus: autoFocus, + scrollEnabled: scrollEnabled, + autoCapitalize: autoCapitalize, + multiline: multiline, + cursorColor: cursorColor, + selectionColor: selectionColor, + isOnChangeMarkdownSet: onChangeMarkdown !== undefined, + onChangeText: handleChangeText, + onChangeMarkdown: handleChangeMarkdown, + onChangeSelection: handleChangeSelection, + onChangeState: handleChangeState, + onLinkDetected: handleLinkDetected, + onInputFocus: handleFocus, + onInputBlur: handleBlur, + onRequestMarkdownResult: handleRequestMarkdownResult, + onRequestCaretRectResult: handleRequestCaretRectResult, + onCaretRectChange: handleCaretRectChange, + contextMenuItems: nativeContextMenuItems, + onContextMenuItemPress: handleContextMenuItemPress, + linkRegex: linkRegex + }); +}; +export default EnrichedMarkdownTextInput; +//# sourceMappingURL=EnrichedMarkdownTextInput.js.map \ No newline at end of file diff --git a/lib/module/EnrichedMarkdownTextInput.js.map b/lib/module/EnrichedMarkdownTextInput.js.map new file mode 100644 index 00000000..b93de7f4 --- /dev/null +++ b/lib/module/EnrichedMarkdownTextInput.js.map @@ -0,0 +1 @@ +{"version":3,"names":["useCallback","useEffect","useImperativeHandle","useMemo","useRef","EnrichedMarkdownTextInputNativeComponent","Commands","normalizeMarkdownTextInputStyle","toNativeRegexConfig","jsx","_jsx","getNativeRef","ref","current","Error","EnrichedMarkdownTextInput","markdownStyle","style","defaultValue","placeholder","placeholderTextColor","editable","autoFocus","scrollEnabled","autoCapitalize","multiline","cursorColor","selectionColor","onChangeText","onChangeMarkdown","onChangeSelection","onChangeState","onCaretRectChange","onLinkDetected","onFocus","onBlur","contextMenuItems","linkRegex","_linkRegex","nativeRef","nextRequestId","pendingRequests","Map","pendingCaretRectRequests","contextMenuCallbacksRef","callbacksMap","item","set","text","onPress","nativeContextMenuItems","filter","visible","map","icon","pending","pendingCaretRect","err","forEach","reject","clear","normalizedStyle","handleLinkDetected","e","url","start","end","nativeEvent","handleChangeText","value","handleChangeMarkdown","handleChangeSelection","handleChangeState","bold","italic","underline","strikethrough","spoiler","link","handleCaretRectChange","x","y","width","height","handleFocus","handleBlur","handleRequestMarkdownResult","requestId","markdown","get","resolve","delete","handleRequestCaretRectResult","handleContextMenuItemPress","itemText","selectedText","selectionStart","selectionEnd","styleState","callback","selection","node","commandRef","measure","measureInWindow","measureLayout","relativeToNativeNode","onSuccess","onFail","focus","blur","setValue","setSelection","toggleBold","toggleItalic","toggleUnderline","toggleStrikethrough","toggleSpoiler","setLink","insertLink","removeLink","getMarkdown","Promise","requestMarkdown","getCaretRect","requestCaretRect","isOnChangeMarkdownSet","undefined","onInputFocus","onInputBlur","onRequestMarkdownResult","onRequestCaretRectResult","onContextMenuItemPress"],"sourceRoot":"../../src","sources":["EnrichedMarkdownTextInput.tsx"],"mappings":";;AAAA,SACEA,WAAW,EACXC,SAAS,EACTC,mBAAmB,EACnBC,OAAO,EACPC,MAAM,QACD,OAAO;AAEd,OAAOC,wCAAwC,IAC7CC,QAAQ,QAWH,4CAA4C;AASnD,SAASC,+BAA+B,QAAQ,sCAAmC;AACnF,SAASC,mBAAmB,QAAQ,wBAAqB;AAAC,SAAAC,GAAA,IAAAC,IAAA;AAoG1D,SAASC,YAAYA,CAACC,GAAsC,EAAa;EACvE,IAAIA,GAAG,CAACC,OAAO,IAAI,IAAI,EAAE;IACvB,MAAM,IAAIC,KAAK,CACb,yFACF,CAAC;EACH;EACA,OAAOF,GAAG,CAACC,OAAO;AACpB;AAEA,OAAO,MAAME,yBAAyB,GAAGA,CAAC;EACxCH,GAAG;EACHI,aAAa;EACbC,KAAK;EACLC,YAAY;EACZC,WAAW;EACXC,oBAAoB;EACpBC,QAAQ,GAAG,IAAI;EACfC,SAAS,GAAG,KAAK;EACjBC,aAAa,GAAG,IAAI;EACpBC,cAAc,GAAG,WAAW;EAC5BC,SAAS,GAAG,IAAI;EAChBC,WAAW;EACXC,cAAc;EACdC,YAAY;EACZC,gBAAgB;EAChBC,iBAAiB;EACjBC,aAAa;EACbC,iBAAiB;EACjBC,cAAc;EACdC,OAAO;EACPC,MAAM;EACNC,gBAAgB;EAChBC,SAAS,EAAEC;AACmB,CAAC,KAAK;EACpC,MAAMC,SAAS,GAAGnC,MAAM,CAAmB,IAAI,CAAC;EAEhD,MAAMoC,aAAa,GAAGpC,MAAM,CAAC,CAAC,CAAC;EAC/B,MAAMqC,eAAe,GAAGrC,MAAM,CAAC,IAAIsC,GAAG,CAAiC,CAAC,CAAC;EACzE,MAAMC,wBAAwB,GAAGvC,MAAM,CACrC,IAAIsC,GAAG,CAAoC,CAC7C,CAAC;EAED,MAAME,uBAAuB,GAAGxC,MAAM,CAEpC,IAAIsC,GAAG,CAAC,CAAC,CAAC;EAEZzC,SAAS,CAAC,MAAM;IACd,MAAM4C,YAAY,GAAG,IAAIH,GAAG,CAAqC,CAAC;IAClE,IAAIN,gBAAgB,EAAE;MACpB,KAAK,MAAMU,IAAI,IAAIV,gBAAgB,EAAE;QACnCS,YAAY,CAACE,GAAG,CAACD,IAAI,CAACE,IAAI,EAAEF,IAAI,CAACG,OAAO,CAAC;MAC3C;IACF;IACAL,uBAAuB,CAAC/B,OAAO,GAAGgC,YAAY;EAChD,CAAC,EAAE,CAACT,gBAAgB,CAAC,CAAC;EAEtB,MAAMc,sBAAsB,GAAG/C,OAAO,CACpC,MACEiC,gBAAgB,EACZe,MAAM,CAAEL,IAAI,IAAKA,IAAI,CAACM,OAAO,KAAK,KAAK,CAAC,CACzCC,GAAG,CAAEP,IAAI,KAAM;IAAEE,IAAI,EAAEF,IAAI,CAACE,IAAI;IAAEM,IAAI,EAAER,IAAI,CAACQ;EAAK,CAAC,CAAC,CAAC,EAC1D,CAAClB,gBAAgB,CACnB,CAAC;EAEDnC,SAAS,CAAC,MAAM;IACd,MAAMsD,OAAO,GAAGd,eAAe,CAAC5B,OAAO;IACvC,MAAM2C,gBAAgB,GAAGb,wBAAwB,CAAC9B,OAAO;IACzD,OAAO,MAAM;MACX,MAAM4C,GAAG,GAAG,IAAI3C,KAAK,CAAC,qBAAqB,CAAC;MAC5CyC,OAAO,CAACG,OAAO,CAAC,CAAC;QAAEC;MAAO,CAAC,KAAKA,MAAM,CAACF,GAAG,CAAC,CAAC;MAC5CF,OAAO,CAACK,KAAK,CAAC,CAAC;MACfJ,gBAAgB,CAACE,OAAO,CAAC,CAAC;QAAEC;MAAO,CAAC,KAAKA,MAAM,CAACF,GAAG,CAAC,CAAC;MACrDD,gBAAgB,CAACI,KAAK,CAAC,CAAC;IAC1B,CAAC;EACH,CAAC,EAAE,EAAE,CAAC;EAEN,MAAMC,eAAe,GAAGtD,+BAA+B,CAACS,aAAa,CAAC;EAEtE,MAAMqB,SAAS,GAAGlC,OAAO,CACvB,MAAMK,mBAAmB,CAAC8B,UAAU,CAAC,EACrC,CAACA,UAAU,CACb,CAAC;EAED,MAAMwB,kBAAkB,GAAG9D,WAAW,CACnC+D,CAAuC,IAAK;IAC3C,MAAM;MAAEf,IAAI;MAAEgB,GAAG;MAAEC,KAAK;MAAEC;IAAI,CAAC,GAAGH,CAAC,CAACI,WAAW;IAC/ClC,cAAc,GAAG;MAAEe,IAAI;MAAEgB,GAAG;MAAEC,KAAK;MAAEC;IAAI,CAAC,CAAC;EAC7C,CAAC,EACD,CAACjC,cAAc,CACjB,CAAC;EAED,MAAMmC,gBAAgB,GAAGpE,WAAW,CACjC+D,CAA0C,IAAK;IAC9CnC,YAAY,GAAGmC,CAAC,CAACI,WAAW,CAACE,KAAK,CAAC;EACrC,CAAC,EACD,CAACzC,YAAY,CACf,CAAC;EAED,MAAM0C,oBAAoB,GAAGtE,WAAW,CACrC+D,CAA8C,IAAK;IAClDlC,gBAAgB,GAAGkC,CAAC,CAACI,WAAW,CAACE,KAAK,CAAC;EACzC,CAAC,EACD,CAACxC,gBAAgB,CACnB,CAAC;EAED,MAAM0C,qBAAqB,GAAGvE,WAAW,CACtC+D,CAA+C,IAAK;IACnD,MAAM;MAAEE,KAAK;MAAEC;IAAI,CAAC,GAAGH,CAAC,CAACI,WAAW;IACpCrC,iBAAiB,GAAG;MAAEmC,KAAK;MAAEC;IAAI,CAAC,CAAC;EACrC,CAAC,EACD,CAACpC,iBAAiB,CACpB,CAAC;EAED,MAAM0C,iBAAiB,GAAGxE,WAAW,CAClC+D,CAA2C,IAAK;IAC/C,MAAM;MAAEU,IAAI;MAAEC,MAAM;MAAEC,SAAS;MAAEC,aAAa;MAAEC,OAAO;MAAEC;IAAK,CAAC,GAC7Df,CAAC,CAACI,WAAW;IACfpC,aAAa,GAAG;MACd0C,IAAI;MACJC,MAAM;MACNC,SAAS;MACTC,aAAa;MACbC,OAAO;MACPC;IACF,CAAC,CAAC;EACJ,CAAC,EACD,CAAC/C,aAAa,CAChB,CAAC;EAED,MAAMgD,qBAAqB,GAAG/E,WAAW,CACtC+D,CAA+C,IAAK;IACnD,MAAM;MAAEiB,CAAC;MAAEC,CAAC;MAAEC,KAAK;MAAEC;IAAO,CAAC,GAAGpB,CAAC,CAACI,WAAW;IAC7CnC,iBAAiB,GAAG;MAAEgD,CAAC;MAAEC,CAAC;MAAEC,KAAK;MAAEC;IAAO,CAAC,CAAC;EAC9C,CAAC,EACD,CAACnD,iBAAiB,CACpB,CAAC;EAED,MAAMoD,WAAW,GAAGpF,WAAW,CAAC,MAAM;IACpCkC,OAAO,GAAG,CAAC;EACb,CAAC,EAAE,CAACA,OAAO,CAAC,CAAC;EAEb,MAAMmD,UAAU,GAAGrF,WAAW,CAAC,MAAM;IACnCmC,MAAM,GAAG,CAAC;EACZ,CAAC,EAAE,CAACA,MAAM,CAAC,CAAC;EAEZ,MAAMmD,2BAA2B,GAAGtF,WAAW,CAC5C+D,CAAqD,IAAK;IACzD,MAAM;MAAEwB,SAAS;MAAEC;IAAS,CAAC,GAAGzB,CAAC,CAACI,WAAW;IAC7C,MAAMZ,OAAO,GAAGd,eAAe,CAAC5B,OAAO,CAAC4E,GAAG,CAACF,SAAS,CAAC;IACtD,IAAI,CAAChC,OAAO,EAAE;IAEdA,OAAO,CAACmC,OAAO,CAACF,QAAQ,CAAC;IACzB/C,eAAe,CAAC5B,OAAO,CAAC8E,MAAM,CAACJ,SAAS,CAAC;EAC3C,CAAC,EACD,EACF,CAAC;EAED,MAAMK,4BAA4B,GAAG5F,WAAW,CAC7C+D,CAAsD,IAAK;IAC1D,MAAM;MAAEwB,SAAS;MAAEP,CAAC;MAAEC,CAAC;MAAEC,KAAK;MAAEC;IAAO,CAAC,GAAGpB,CAAC,CAACI,WAAW;IACxD,MAAMZ,OAAO,GAAGZ,wBAAwB,CAAC9B,OAAO,CAAC4E,GAAG,CAACF,SAAS,CAAC;IAC/D,IAAI,CAAChC,OAAO,EAAE;IAEdA,OAAO,CAACmC,OAAO,CAAC;MAAEV,CAAC;MAAEC,CAAC;MAAEC,KAAK;MAAEC;IAAO,CAAC,CAAC;IACxCxC,wBAAwB,CAAC9B,OAAO,CAAC8E,MAAM,CAACJ,SAAS,CAAC;EACpD,CAAC,EACD,EACF,CAAC;EAED,MAAMM,0BAA0B,GAAG7F,WAAW,CAC3C+D,CAAoD,IAAK;IACxD,MAAM;MACJ+B,QAAQ;MACRC,YAAY;MACZC,cAAc;MACdC,YAAY;MACZC;IACF,CAAC,GAAGnC,CAAC,CAACI,WAAW;IACjB,MAAMgC,QAAQ,GAAGvD,uBAAuB,CAAC/B,OAAO,CAAC4E,GAAG,CAACK,QAAQ,CAAC;IAC9DK,QAAQ,GAAG;MACTnD,IAAI,EAAE+C,YAAY;MAClBK,SAAS,EAAE;QAAEnC,KAAK,EAAE+B,cAAc;QAAE9B,GAAG,EAAE+B;MAAa,CAAC;MACvDC;IACF,CAAC,CAAC;EACJ,CAAC,EACD,EACF,CAAC;EAEDhG,mBAAmB,CAACU,GAAG,EAAE,MAAM;IAC7B,MAAMyF,IAAI,GAAG1F,YAAY,CAAC4B,SAAS,CAAC;IACpC;IACA;IACA,MAAM+D,UAAU,GAAGD,IAAiD;IACpE,OAAO;MACLE,OAAO,EAAGJ,QAAQ,IAAKE,IAAI,CAACE,OAAO,CAACJ,QAAQ,CAAC;MAC7CK,eAAe,EAAGL,QAAQ,IAAKE,IAAI,CAACG,eAAe,CAACL,QAAQ,CAAC;MAC7DM,aAAa,EAAEA,CAACC,oBAAoB,EAAEC,SAAS,EAAEC,MAAM,KACrDP,IAAI,CAACI,aAAa,CAACC,oBAAoB,EAAEC,SAAS,EAAEC,MAAM,CAAC;MAC7DC,KAAK,EAAEA,CAAA,KAAMvG,QAAQ,CAACuG,KAAK,CAACP,UAAU,CAAC;MACvCQ,IAAI,EAAEA,CAAA,KAAMxG,QAAQ,CAACwG,IAAI,CAACR,UAAU,CAAC;MACrCS,QAAQ,EAAGvB,QAAQ,IAAKlF,QAAQ,CAACyG,QAAQ,CAACT,UAAU,EAAEd,QAAQ,CAAC;MAC/DwB,YAAY,EAAEA,CAAC/C,KAAK,EAAEC,GAAG,KACvB5D,QAAQ,CAAC0G,YAAY,CAACV,UAAU,EAAErC,KAAK,EAAEC,GAAG,CAAC;MAC/C+C,UAAU,EAAEA,CAAA,KAAM3G,QAAQ,CAAC2G,UAAU,CAACX,UAAU,CAAC;MACjDY,YAAY,EAAEA,CAAA,KAAM5G,QAAQ,CAAC4G,YAAY,CAACZ,UAAU,CAAC;MACrDa,eAAe,EAAEA,CAAA,KAAM7G,QAAQ,CAAC6G,eAAe,CAACb,UAAU,CAAC;MAC3Dc,mBAAmB,EAAEA,CAAA,KAAM9G,QAAQ,CAAC8G,mBAAmB,CAACd,UAAU,CAAC;MACnEe,aAAa,EAAEA,CAAA,KAAM/G,QAAQ,CAAC+G,aAAa,CAACf,UAAU,CAAC;MACvDgB,OAAO,EAAGtD,GAAG,IAAK1D,QAAQ,CAACgH,OAAO,CAAChB,UAAU,EAAEtC,GAAG,CAAC;MACnDuD,UAAU,EAAEA,CAACvE,IAAI,EAAEgB,GAAG,KAAK1D,QAAQ,CAACiH,UAAU,CAACjB,UAAU,EAAEtD,IAAI,EAAEgB,GAAG,CAAC;MACrEwD,UAAU,EAAEA,CAAA,KAAMlH,QAAQ,CAACkH,UAAU,CAAClB,UAAU,CAAC;MACjDmB,WAAW,EAAEA,CAAA,KACX,IAAIC,OAAO,CAAS,CAAChC,OAAO,EAAE/B,MAAM,KAAK;QACvC,MAAM4B,SAAS,GAAG/C,aAAa,CAAC3B,OAAO,EAAE;QACzC4B,eAAe,CAAC5B,OAAO,CAACkC,GAAG,CAACwC,SAAS,EAAE;UAAEG,OAAO;UAAE/B;QAAO,CAAC,CAAC;QAC3DrD,QAAQ,CAACqH,eAAe,CAACrB,UAAU,EAAEf,SAAS,CAAC;MACjD,CAAC,CAAC;MACJqC,YAAY,EAAEA,CAAA,KACZ,IAAIF,OAAO,CAAY,CAAChC,OAAO,EAAE/B,MAAM,KAAK;QAC1C,MAAM4B,SAAS,GAAG/C,aAAa,CAAC3B,OAAO,EAAE;QACzC8B,wBAAwB,CAAC9B,OAAO,CAACkC,GAAG,CAACwC,SAAS,EAAE;UAC9CG,OAAO;UACP/B;QACF,CAAC,CAAC;QACFrD,QAAQ,CAACuH,gBAAgB,CAACvB,UAAU,EAAEf,SAAS,CAAC;MAClD,CAAC;IACL,CAAC;EACH,CAAC,CAAC;EAEF,oBACE7E,IAAA,CAACL,wCAAwC;IACvCO,GAAG,EAAE2B,SAAU;IACftB,KAAK,EAAEA,KAAM;IACbD,aAAa,EAAE6C,eAAgB;IAC/B3C,YAAY,EAAEA,YAAa;IAC3BC,WAAW,EAAEA,WAAY;IACzBC,oBAAoB,EAAEA,oBAAqB;IAC3CC,QAAQ,EAAEA,QAAS;IACnBC,SAAS,EAAEA,SAAU;IACrBC,aAAa,EAAEA,aAAc;IAC7BC,cAAc,EAAEA,cAAe;IAC/BC,SAAS,EAAEA,SAAU;IACrBC,WAAW,EAAEA,WAAY;IACzBC,cAAc,EAAEA,cAAe;IAC/BmG,qBAAqB,EAAEjG,gBAAgB,KAAKkG,SAAU;IACtDnG,YAAY,EAAEwC,gBAAgD;IAC9DvC,gBAAgB,EAAEyC,oBAAwD;IAC1ExC,iBAAiB,EACfyC,qBACD;IACDxC,aAAa,EAAEyC,iBAAkD;IACjEvC,cAAc,EAAE6B,kBAAoD;IACpEkE,YAAY,EAAE5C,WAA2C;IACzD6C,WAAW,EAAE5C,UAAyC;IACtD6C,uBAAuB,EACrB5C,2BACD;IACD6C,wBAAwB,EACtBvC,4BACD;IACD5D,iBAAiB,EACf+C,qBACD;IACD3C,gBAAgB,EAAEc,sBAAuB;IACzCkF,sBAAsB,EACpBvC,0BACD;IACDxD,SAAS,EAAEA;EAAU,CACtB,CAAC;AAEN,CAAC;AAED,eAAetB,yBAAyB","ignoreList":[]} diff --git a/lib/module/EnrichedMarkdownTextInputNativeComponent.ts b/lib/module/EnrichedMarkdownTextInputNativeComponent.ts new file mode 100644 index 00000000..d9368251 --- /dev/null +++ b/lib/module/EnrichedMarkdownTextInputNativeComponent.ts @@ -0,0 +1,259 @@ +import { + codegenNativeComponent, + codegenNativeCommands, + type ViewProps, + type ColorValue, + type HostComponent, + type CodegenTypes, +} from 'react-native'; +import type React from 'react'; + +interface MarkdownTextInputStyleInternal { + strong: { + color?: ColorValue; + }; + em: { + color?: ColorValue; + }; + link: { + color: ColorValue; + underline: boolean; + }; + spoiler: { + color: ColorValue; + backgroundColor: ColorValue; + }; +} + +interface TargetedEvent { + target: CodegenTypes.Int32; +} + +export interface OnChangeTextEvent { + value: string; +} + +export interface OnChangeMarkdownEvent { + value: string; +} + +export interface OnChangeSelectionEvent { + start: CodegenTypes.Int32; + end: CodegenTypes.Int32; +} + +export interface OnChangeStateEvent { + bold: { isActive: boolean }; + italic: { isActive: boolean }; + underline: { isActive: boolean }; + strikethrough: { isActive: boolean }; + spoiler: { isActive: boolean }; + link: { isActive: boolean }; +} + +export interface OnRequestMarkdownResultEvent { + requestId: CodegenTypes.Int32; + markdown: string; +} + +export interface OnRequestCaretRectResultEvent { + requestId: CodegenTypes.Int32; + x: CodegenTypes.Double; + y: CodegenTypes.Double; + width: CodegenTypes.Double; + height: CodegenTypes.Double; +} + +export interface OnCaretRectChangeEvent { + x: CodegenTypes.Double; + y: CodegenTypes.Double; + width: CodegenTypes.Double; + height: CodegenTypes.Double; +} + +export interface LinkNativeRegex { + pattern: string; + caseInsensitive: boolean; + dotAll: boolean; + isDisabled: boolean; + isDefault: boolean; +} + +export interface OnLinkDetected { + text: string; + url: string; + start: CodegenTypes.Int32; + end: CodegenTypes.Int32; +} + +export interface ContextMenuItemConfig { + text: string; + icon?: string; +} + +export interface OnContextMenuItemPressEvent { + itemText: string; + selectedText: string; + selectionStart: CodegenTypes.Int32; + selectionEnd: CodegenTypes.Int32; + styleState: { + bold: { isActive: boolean }; + italic: { isActive: boolean }; + underline: { isActive: boolean }; + strikethrough: { isActive: boolean }; + spoiler: { isActive: boolean }; + link: { isActive: boolean }; + }; +} + +export interface NativeProps extends ViewProps { + /** + * Initial markdown content. + */ + defaultValue?: string; + /** + * Placeholder text shown when the input is empty. + */ + placeholder?: string; + /** + * Color of the placeholder text. + */ + placeholderTextColor?: ColorValue; + /** + * Whether the input is editable. + * @default true + */ + editable?: boolean; + /** + * Whether the input should auto-focus on mount. + * @default false + */ + autoFocus?: boolean; + /** + * Whether the input is scrollable. + * @default true + */ + scrollEnabled?: boolean; + /** + * Auto-capitalization behavior. + */ + autoCapitalize?: string; + /** + * Whether the input supports multiple lines. + * @default true + */ + multiline?: boolean; + /** + * Color of the cursor. + */ + cursorColor?: ColorValue; + /** + * Color of the text selection highlight. + */ + selectionColor?: ColorValue; + /** + * Inline format style overrides. + * Always provided with complete defaults via normalizeMarkdownTextInputStyle. + */ + markdownStyle: MarkdownTextInputStyleInternal; + + // These should not be passed as regular props. + color?: ColorValue; + fontSize?: CodegenTypes.Float; + lineHeight?: CodegenTypes.Float; + fontFamily?: string; + fontWeight?: string; + + /** + * Whether onChangeMarkdown handler is set. When true, the native side + * serializes formatting ranges to Markdown on every change. + */ + isOnChangeMarkdownSet?: boolean; + + /** + * Custom items to show in the text selection context menu. + * Each item is shown by its `text` label; invisible items should be filtered out before passing here. + */ + contextMenuItems?: ReadonlyArray>; + + /** + * Regex configuration for automatic link detection. + * Omit or pass undefined to use platform defaults. + */ + linkRegex?: Readonly; + + // Events + onChangeText?: CodegenTypes.DirectEventHandler; + onChangeMarkdown?: CodegenTypes.DirectEventHandler; + onChangeSelection?: CodegenTypes.DirectEventHandler; + onChangeState?: CodegenTypes.DirectEventHandler; + onInputFocus?: CodegenTypes.DirectEventHandler; + onInputBlur?: CodegenTypes.DirectEventHandler; + onRequestMarkdownResult?: CodegenTypes.DirectEventHandler; + onRequestCaretRectResult?: CodegenTypes.DirectEventHandler; + onCaretRectChange?: CodegenTypes.DirectEventHandler; + onContextMenuItemPress?: CodegenTypes.DirectEventHandler; + onLinkDetected?: CodegenTypes.DirectEventHandler; +} + +type ComponentType = HostComponent; + +interface NativeCommands { + focus: (viewRef: React.ElementRef) => void; + blur: (viewRef: React.ElementRef) => void; + setValue: ( + viewRef: React.ElementRef, + markdown: string + ) => void; + setSelection: ( + viewRef: React.ElementRef, + start: CodegenTypes.Int32, + end: CodegenTypes.Int32 + ) => void; + toggleBold: (viewRef: React.ElementRef) => void; + toggleItalic: (viewRef: React.ElementRef) => void; + toggleUnderline: (viewRef: React.ElementRef) => void; + toggleStrikethrough: (viewRef: React.ElementRef) => void; + toggleSpoiler: (viewRef: React.ElementRef) => void; + setLink: (viewRef: React.ElementRef, url: string) => void; + insertLink: ( + viewRef: React.ElementRef, + text: string, + url: string + ) => void; + removeLink: (viewRef: React.ElementRef) => void; + requestMarkdown: ( + viewRef: React.ElementRef, + requestId: CodegenTypes.Int32 + ) => void; + requestCaretRect: ( + viewRef: React.ElementRef, + requestId: CodegenTypes.Int32 + ) => void; +} + +export const Commands: NativeCommands = codegenNativeCommands({ + supportedCommands: [ + 'focus', + 'blur', + 'setValue', + 'setSelection', + 'toggleBold', + 'toggleItalic', + 'toggleUnderline', + 'toggleStrikethrough', + 'toggleSpoiler', + 'setLink', + 'insertLink', + 'removeLink', + 'requestMarkdown', + 'requestCaretRect', + ], +}); + +export default codegenNativeComponent( + 'EnrichedMarkdownTextInput', + { + interfaceOnly: true, + } +) as HostComponent; diff --git a/lib/module/EnrichedMarkdownTextNativeComponent.ts b/lib/module/EnrichedMarkdownTextNativeComponent.ts new file mode 100644 index 00000000..56a8ec60 --- /dev/null +++ b/lib/module/EnrichedMarkdownTextNativeComponent.ts @@ -0,0 +1,392 @@ +import { + codegenNativeComponent, + type ViewProps, + type CodegenTypes, + type ColorValue, +} from 'react-native'; + +// All block styles extend this interface +interface BaseBlockStyleInternal { + fontSize: CodegenTypes.Float; + fontFamily: string; + fontWeight: string; + color: ColorValue; + marginTop: CodegenTypes.Float; + marginBottom: CodegenTypes.Float; + lineHeight: CodegenTypes.Float; +} + +interface ParagraphStyleInternal extends BaseBlockStyleInternal { + textAlign: string; +} + +interface HeadingStyleInternal extends BaseBlockStyleInternal { + textAlign: string; +} + +interface BlockquoteStyleInternal extends BaseBlockStyleInternal { + borderColor: ColorValue; + borderWidth: CodegenTypes.Float; + gapWidth: CodegenTypes.Float; + backgroundColor: ColorValue; +} + +interface ListStyleInternal extends BaseBlockStyleInternal { + bulletColor: ColorValue; + bulletSize: CodegenTypes.Float; + markerMinWidth: CodegenTypes.Float; + markerColor: ColorValue; + markerFontWeight: string; + gapWidth: CodegenTypes.Float; + marginLeft: CodegenTypes.Float; +} + +interface CodeBlockStyleInternal extends BaseBlockStyleInternal { + backgroundColor: ColorValue; + borderColor: ColorValue; + borderRadius: CodegenTypes.Float; + borderWidth: CodegenTypes.Float; + padding: CodegenTypes.Float; +} + +interface LinkStyleInternal { + fontFamily: string; + color: ColorValue; + underline: boolean; +} + +interface StrongStyleInternal { + fontFamily: string; + fontWeight: string; + color?: ColorValue; +} + +interface EmphasisStyleInternal { + fontFamily: string; + fontStyle: string; + color?: ColorValue; +} + +interface StrikethroughStyleInternal { + color: ColorValue; +} + +interface UnderlineStyleInternal { + color: ColorValue; +} + +interface CodeStyleInternal { + fontFamily: string; + fontSize: CodegenTypes.Float; + color: ColorValue; + backgroundColor: ColorValue; + borderColor: ColorValue; +} + +interface ImageStyleInternal { + height: CodegenTypes.Float; + borderRadius: CodegenTypes.Float; + marginTop: CodegenTypes.Float; + marginBottom: CodegenTypes.Float; +} + +interface InlineImageStyleInternal { + size: CodegenTypes.Float; +} + +interface ThematicBreakStyleInternal { + color: ColorValue; + height: CodegenTypes.Float; + marginTop: CodegenTypes.Float; + marginBottom: CodegenTypes.Float; +} + +interface TableStyleInternal extends BaseBlockStyleInternal { + headerFontFamily: string; + headerBackgroundColor: ColorValue; + headerTextColor: ColorValue; + rowEvenBackgroundColor: ColorValue; + rowOddBackgroundColor: ColorValue; + borderColor: ColorValue; + borderWidth: CodegenTypes.Float; + borderRadius: CodegenTypes.Float; + cellPaddingHorizontal: CodegenTypes.Float; + cellPaddingVertical: CodegenTypes.Float; +} + +interface TaskListStyleInternal { + checkedColor: ColorValue; + borderColor: ColorValue; + checkboxSize: CodegenTypes.Float; + checkboxBorderRadius: CodegenTypes.Float; + checkmarkColor: ColorValue; + checkedTextColor: ColorValue; + checkedStrikethrough: boolean; +} + +interface MathStyleInternal { + fontSize: CodegenTypes.Float; + color: ColorValue; + backgroundColor: ColorValue; + padding: CodegenTypes.Float; + marginTop: CodegenTypes.Float; + marginBottom: CodegenTypes.Float; + textAlign: string; +} + +interface InlineMathStyleInternal { + color: ColorValue; +} + +interface SpoilerParticlesStyleInternal { + density: CodegenTypes.Float; + speed: CodegenTypes.Float; +} + +interface SpoilerSolidStyleInternal { + borderRadius: CodegenTypes.Float; +} + +interface SpoilerStyleInternal { + color: ColorValue; + particles: SpoilerParticlesStyleInternal; + solid: SpoilerSolidStyleInternal; +} + +interface MentionStyleInternal { + color: ColorValue; + backgroundColor: ColorValue; + borderColor: ColorValue; + borderWidth: CodegenTypes.Float; + borderRadius: CodegenTypes.Float; + paddingHorizontal: CodegenTypes.Float; + paddingVertical: CodegenTypes.Float; + fontFamily: string; + fontWeight: string; + fontSize: CodegenTypes.Float; + pressedOpacity: CodegenTypes.Float; +} + +interface CitationStyleInternal { + color: ColorValue; + fontSizeMultiplier: CodegenTypes.Float; + baselineOffsetPx: CodegenTypes.Float; + fontWeight: string; + underline: boolean; + backgroundColor: ColorValue; + paddingHorizontal: CodegenTypes.Float; + paddingVertical: CodegenTypes.Float; + borderColor: ColorValue; + borderWidth: CodegenTypes.Float; + borderRadius: CodegenTypes.Float; +} + +export interface MarkdownStyleInternal { + paragraph: ParagraphStyleInternal; + h1: HeadingStyleInternal; + h2: HeadingStyleInternal; + h3: HeadingStyleInternal; + h4: HeadingStyleInternal; + h5: HeadingStyleInternal; + h6: HeadingStyleInternal; + blockquote: BlockquoteStyleInternal; + list: ListStyleInternal; + codeBlock: CodeBlockStyleInternal; + link: LinkStyleInternal; + strong: StrongStyleInternal; + em: EmphasisStyleInternal; + strikethrough: StrikethroughStyleInternal; + underline: UnderlineStyleInternal; + code: CodeStyleInternal; + image: ImageStyleInternal; + inlineImage: InlineImageStyleInternal; + thematicBreak: ThematicBreakStyleInternal; + table: TableStyleInternal; + taskList: TaskListStyleInternal; + math: MathStyleInternal; + inlineMath: InlineMathStyleInternal; + spoiler: SpoilerStyleInternal; + mention: MentionStyleInternal; + citation: CitationStyleInternal; +} + +export interface LinkPressEvent { + url: string; +} + +export interface LinkLongPressEvent { + url: string; +} + +export interface MentionPressEvent { + url: string; + text: string; +} + +export interface CitationPressEvent { + url: string; + text: string; +} + +export interface TaskListItemPressEvent { + index: CodegenTypes.Int32; + checked: boolean; + text: string; +} + +export interface ContextMenuItemConfig { + text: string; + icon?: string; +} + +export interface OnContextMenuItemPressEvent { + itemText: string; + selectedText: string; + selectionStart: CodegenTypes.Int32; + selectionEnd: CodegenTypes.Int32; +} + +/** + * MD4C parser flags configuration. + * Controls how the markdown parser interprets certain syntax. + */ +export interface Md4cFlagsInternal { + /** + * Enable underline syntax support (__text__). + * When enabled, underscores are treated as underline markers. + * When disabled, underscores are treated as emphasis markers (same as asterisks). + * @default false + */ + underline: boolean; + /** + * Enable LaTeX math span parsing ($..$ and $$..$$). + * When disabled, dollar signs are treated as plain text. + * @default true + */ + latexMath: boolean; +} + +export interface NativeProps extends ViewProps { + /** + * Markdown content to render. + */ + markdown: string; + /** + * Internal style configuration for markdown elements. + * Always provided with complete defaults via normalizeMarkdownStyle. + * Block styles (paragraph, headings) contain fontSize, fontFamily, fontWeight, and color. + */ + markdownStyle: MarkdownStyleInternal; + /** + * Callback fired when a link is pressed. + * Receives the URL that was tapped. + */ + onLinkPress?: CodegenTypes.BubblingEventHandler; + /** + * Callback fired when a link is long pressed. + * Receives the URL that was long pressed. + * - iOS: When provided, overrides the system link preview behavior. + * - Android: Handles long press gestures on links. + */ + onLinkLongPress?: CodegenTypes.BubblingEventHandler; + /** + * Callback fired when a task list checkbox is tapped. + * Receives the 0-based task index, current checked state, and the item's plain text. + */ + onTaskListItemPress?: CodegenTypes.BubblingEventHandler; + /** + * Callback fired when an inline mention pill (`mention://`) is pressed. + */ + onMentionPress?: CodegenTypes.BubblingEventHandler; + /** + * Callback fired when an inline citation (`citation://`) is pressed. + */ + onCitationPress?: CodegenTypes.BubblingEventHandler; + /** + * Controls whether the system link preview is shown on long press (iOS only). + * + * When `true` (default), long-pressing a link shows the native iOS link preview. + * When `false`, the system preview is suppressed. + * + * Automatically set to `false` when `onLinkLongPress` is provided (unless explicitly overridden). + * + * Android: No-op (Android doesn't have a system link preview). + * + * @default true + */ + enableLinkPreview?: CodegenTypes.WithDefault; + /** + * - iOS: Controls text selection and link previews on long press. + * - Android: Controls text selection. + * @default true + */ + selectable?: boolean; + /** + * Color of the text selection highlight. + * + * On iOS, this also affects the caret and selection handle colors + * (they share a single tint). + * + * @platform ios, android, web + */ + selectionColor?: ColorValue; + /** + * Color of the selection handles (drag anchors). + * No-op on API levels below 29. + * + * @platform android + */ + selectionHandleColor?: ColorValue; + /** + * MD4C parser flags configuration. + * Controls how the markdown parser interprets certain syntax. + */ + md4cFlags: Md4cFlagsInternal; + /** + * Specifies whether fonts should scale to respect Text Size accessibility settings. + * When false, text will not scale with the user's accessibility settings. + * @default true + */ + allowFontScaling?: CodegenTypes.WithDefault; + /** + * Specifies the largest possible scale a font can reach when allowFontScaling is enabled. + * Possible values: + * - undefined/null (default): inherit from parent or global default (no limit) + * - 0: no limit, ignore parent/global default + * - >= 1: sets the maxFontSizeMultiplier of this node to this value + * @default undefined + */ + maxFontSizeMultiplier?: CodegenTypes.Float; + /** + * When false (default), removes trailing margin from the last element to eliminate bottom spacing. + * When true, keeps the trailing margin from the last element's marginBottom style. + * @default false + */ + allowTrailingMargin?: CodegenTypes.WithDefault; + /** + * When true, newly appended content fades in during streaming updates. + * Only the tail (new characters beyond the previous content) is animated. + * @default false + */ + streamingAnimation?: CodegenTypes.WithDefault; + /** + * Controls how spoiler text is displayed before being revealed. + * - 'particles' (default): animated particle overlay. + * - 'solid': opaque rectangle covering the text. + * @default 'particles' + */ + spoilerOverlay?: CodegenTypes.WithDefault; + /** + * Custom items to show in the text selection context menu. + */ + contextMenuItems?: ReadonlyArray>; + /** + * Fired when a custom context menu item is pressed. + * Receives the item label, the currently selected text, and the selection range. + */ + onContextMenuItemPress?: CodegenTypes.BubblingEventHandler; +} + +export default codegenNativeComponent('EnrichedMarkdownText', { + interfaceOnly: true, +}); diff --git a/lib/module/index.js b/lib/module/index.js new file mode 100644 index 00000000..18b1bd1f --- /dev/null +++ b/lib/module/index.js @@ -0,0 +1,5 @@ +"use strict"; + +export { default as EnrichedMarkdownText } from "./native/EnrichedMarkdownText.js"; +export { EnrichedMarkdownTextInput } from "./EnrichedMarkdownTextInput.js"; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/lib/module/index.js.map b/lib/module/index.js.map new file mode 100644 index 00000000..9ee8da96 --- /dev/null +++ b/lib/module/index.js.map @@ -0,0 +1 @@ +{"version":3,"names":["default","EnrichedMarkdownText","EnrichedMarkdownTextInput"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;AAAA,SAASA,OAAO,IAAIC,oBAAoB,QAAQ,kCAA+B;AAe/E,SAASC,yBAAyB,QAAQ,gCAA6B","ignoreList":[]} diff --git a/lib/module/index.web.js b/lib/module/index.web.js new file mode 100644 index 00000000..d8308e62 --- /dev/null +++ b/lib/module/index.web.js @@ -0,0 +1,4 @@ +"use strict"; + +export { EnrichedMarkdownText, default } from "./web/EnrichedMarkdownText.js"; +//# sourceMappingURL=index.web.js.map \ No newline at end of file diff --git a/lib/module/index.web.js.map b/lib/module/index.web.js.map new file mode 100644 index 00000000..2691825e --- /dev/null +++ b/lib/module/index.web.js.map @@ -0,0 +1 @@ +{"version":3,"names":["EnrichedMarkdownText","default"],"sourceRoot":"../../src","sources":["index.web.tsx"],"mappings":";;AAAA,SAASA,oBAAoB,EAAEC,OAAO,QAAQ,+BAA4B","ignoreList":[]} diff --git a/lib/module/native/EnrichedMarkdownText.js b/lib/module/native/EnrichedMarkdownText.js new file mode 100644 index 00000000..74cae237 --- /dev/null +++ b/lib/module/native/EnrichedMarkdownText.js @@ -0,0 +1,158 @@ +"use strict"; + +import { useMemo, useCallback, useRef, useEffect } from 'react'; +import EnrichedMarkdownTextNativeComponent from '../EnrichedMarkdownTextNativeComponent'; +import EnrichedMarkdownNativeComponent from '../EnrichedMarkdownNativeComponent'; +import { normalizeMarkdownStyle } from '../normalizeMarkdownStyle'; +import { jsx as _jsx } from "react/jsx-runtime"; +const defaultMd4cFlags = { + underline: false, + latexMath: true +}; +export const EnrichedMarkdownText = ({ + markdown, + markdownStyle = {}, + containerStyle, + onLinkPress, + onLinkLongPress, + onTaskListItemPress, + onMentionPress, + onCitationPress, + enableLinkPreview, + selectable = true, + md4cFlags = defaultMd4cFlags, + allowFontScaling = true, + maxFontSizeMultiplier, + allowTrailingMargin = false, + flavor = 'commonmark', + streamingAnimation = false, + spoilerOverlay = 'particles', + contextMenuItems, + selectionColor, + selectionHandleColor, + ...rest +}) => { + const normalizedStyleRef = useRef(null); + const normalized = normalizeMarkdownStyle(markdownStyle); + // normalizeMarkdownStyle returns cached objects for structurally equal inputs, + // so this referential check is sufficient to preserve a stable prop reference. + if (normalizedStyleRef.current !== normalized) { + normalizedStyleRef.current = normalized; + } + const normalizedStyle = normalizedStyleRef.current; + const normalizedMd4cFlags = useMemo(() => ({ + underline: md4cFlags.underline ?? false, + latexMath: md4cFlags.latexMath ?? true + }), [md4cFlags]); + const contextMenuCallbacksRef = useRef(new Map()); + useEffect(() => { + const callbacksMap = new Map(); + if (contextMenuItems) { + for (const item of contextMenuItems) { + callbacksMap.set(item.text, item.onPress); + } + } + contextMenuCallbacksRef.current = callbacksMap; + }, [contextMenuItems]); + const nativeContextMenuItems = useMemo(() => contextMenuItems?.filter(item => item.visible !== false).map(item => ({ + text: item.text, + icon: item.icon + })), [contextMenuItems]); + const handleContextMenuItemPress = useCallback(e => { + const { + itemText, + selectedText, + selectionStart, + selectionEnd + } = e.nativeEvent; + const callback = contextMenuCallbacksRef.current.get(itemText); + callback?.({ + text: selectedText, + selection: { + start: selectionStart, + end: selectionEnd + } + }); + }, []); + const handleLinkPress = useCallback(e => { + const { + url + } = e.nativeEvent; + onLinkPress?.({ + url + }); + }, [onLinkPress]); + const handleLinkLongPress = useCallback(e => { + const { + url + } = e.nativeEvent; + onLinkLongPress?.({ + url + }); + }, [onLinkLongPress]); + const handleTaskListItemPress = useCallback(e => { + const { + index, + checked, + text + } = e.nativeEvent; + onTaskListItemPress?.({ + index, + checked, + text + }); + }, [onTaskListItemPress]); + const handleMentionPress = useCallback(e => { + const { + url, + text + } = e.nativeEvent; + onMentionPress?.({ + url, + text + }); + }, [onMentionPress]); + const handleCitationPress = useCallback(e => { + const { + url, + text + } = e.nativeEvent; + onCitationPress?.({ + url, + text + }); + }, [onCitationPress]); + const sharedProps = { + markdown, + markdownStyle: normalizedStyle, + onLinkPress: handleLinkPress, + onLinkLongPress: handleLinkLongPress, + onTaskListItemPress: handleTaskListItemPress, + onMentionPress: onMentionPress ? handleMentionPress : undefined, + onCitationPress: onCitationPress ? handleCitationPress : undefined, + enableLinkPreview: onLinkLongPress == null && (enableLinkPreview ?? true), + selectable, + md4cFlags: normalizedMd4cFlags, + allowFontScaling, + maxFontSizeMultiplier, + allowTrailingMargin, + streamingAnimation, + spoilerOverlay, + style: containerStyle, + contextMenuItems: nativeContextMenuItems, + onContextMenuItemPress: handleContextMenuItemPress, + selectionColor, + selectionHandleColor, + ...rest + }; + if (flavor === 'github') { + return /*#__PURE__*/_jsx(EnrichedMarkdownNativeComponent, { + ...sharedProps + }); + } + return /*#__PURE__*/_jsx(EnrichedMarkdownTextNativeComponent, { + ...sharedProps + }); +}; +export default EnrichedMarkdownText; +//# sourceMappingURL=EnrichedMarkdownText.js.map \ No newline at end of file diff --git a/lib/module/native/EnrichedMarkdownText.js.map b/lib/module/native/EnrichedMarkdownText.js.map new file mode 100644 index 00000000..65993fa0 --- /dev/null +++ b/lib/module/native/EnrichedMarkdownText.js.map @@ -0,0 +1 @@ +{"version":3,"names":["useMemo","useCallback","useRef","useEffect","EnrichedMarkdownTextNativeComponent","EnrichedMarkdownNativeComponent","normalizeMarkdownStyle","jsx","_jsx","defaultMd4cFlags","underline","latexMath","EnrichedMarkdownText","markdown","markdownStyle","containerStyle","onLinkPress","onLinkLongPress","onTaskListItemPress","onMentionPress","onCitationPress","enableLinkPreview","selectable","md4cFlags","allowFontScaling","maxFontSizeMultiplier","allowTrailingMargin","flavor","streamingAnimation","spoilerOverlay","contextMenuItems","selectionColor","selectionHandleColor","rest","normalizedStyleRef","normalized","current","normalizedStyle","normalizedMd4cFlags","contextMenuCallbacksRef","Map","callbacksMap","item","set","text","onPress","nativeContextMenuItems","filter","visible","map","icon","handleContextMenuItemPress","e","itemText","selectedText","selectionStart","selectionEnd","nativeEvent","callback","get","selection","start","end","handleLinkPress","url","handleLinkLongPress","handleTaskListItemPress","index","checked","handleMentionPress","handleCitationPress","sharedProps","undefined","style","onContextMenuItemPress"],"sourceRoot":"../../../src","sources":["native/EnrichedMarkdownText.tsx"],"mappings":";;AAAA,SAASA,OAAO,EAAEC,WAAW,EAAEC,MAAM,EAAEC,SAAS,QAAQ,OAAO;AAC/D,OAAOC,mCAAmC,MAAM,wCAAwC;AAExF,OAAOC,+BAA+B,MAAM,oCAAoC;AAChF,SAASC,sBAAsB,QAAQ,2BAA2B;AAAC,SAAAC,GAAA,IAAAC,IAAA;AA0BnE,MAAMC,gBAA2B,GAAG;EAClCC,SAAS,EAAE,KAAK;EAChBC,SAAS,EAAE;AACb,CAAC;AAED,OAAO,MAAMC,oBAAoB,GAAGA,CAAC;EACnCC,QAAQ;EACRC,aAAa,GAAG,CAAC,CAAC;EAClBC,cAAc;EACdC,WAAW;EACXC,eAAe;EACfC,mBAAmB;EACnBC,cAAc;EACdC,eAAe;EACfC,iBAAiB;EACjBC,UAAU,GAAG,IAAI;EACjBC,SAAS,GAAGd,gBAAgB;EAC5Be,gBAAgB,GAAG,IAAI;EACvBC,qBAAqB;EACrBC,mBAAmB,GAAG,KAAK;EAC3BC,MAAM,GAAG,YAAY;EACrBC,kBAAkB,GAAG,KAAK;EAC1BC,cAAc,GAAG,WAAW;EAC5BC,gBAAgB;EAChBC,cAAc;EACdC,oBAAoB;EACpB,GAAGC;AACsB,CAAC,KAAK;EAC/B,MAAMC,kBAAkB,GAAGhC,MAAM,CAA+B,IAAI,CAAC;EACrE,MAAMiC,UAAU,GAAG7B,sBAAsB,CAACQ,aAAa,CAAC;EACxD;EACA;EACA,IAAIoB,kBAAkB,CAACE,OAAO,KAAKD,UAAU,EAAE;IAC7CD,kBAAkB,CAACE,OAAO,GAAGD,UAAU;EACzC;EACA,MAAME,eAAe,GAAGH,kBAAkB,CAACE,OAAQ;EAEnD,MAAME,mBAAmB,GAAGtC,OAAO,CACjC,OAAO;IACLU,SAAS,EAAEa,SAAS,CAACb,SAAS,IAAI,KAAK;IACvCC,SAAS,EAAEY,SAAS,CAACZ,SAAS,IAAI;EACpC,CAAC,CAAC,EACF,CAACY,SAAS,CACZ,CAAC;EAED,MAAMgB,uBAAuB,GAAGrC,MAAM,CAEpC,IAAIsC,GAAG,CAAC,CAAC,CAAC;EAEZrC,SAAS,CAAC,MAAM;IACd,MAAMsC,YAAY,GAAG,IAAID,GAAG,CAAqC,CAAC;IAClE,IAAIV,gBAAgB,EAAE;MACpB,KAAK,MAAMY,IAAI,IAAIZ,gBAAgB,EAAE;QACnCW,YAAY,CAACE,GAAG,CAACD,IAAI,CAACE,IAAI,EAAEF,IAAI,CAACG,OAAO,CAAC;MAC3C;IACF;IACAN,uBAAuB,CAACH,OAAO,GAAGK,YAAY;EAChD,CAAC,EAAE,CAACX,gBAAgB,CAAC,CAAC;EAEtB,MAAMgB,sBAAsB,GAAG9C,OAAO,CACpC,MACE8B,gBAAgB,EACZiB,MAAM,CAAEL,IAAI,IAAKA,IAAI,CAACM,OAAO,KAAK,KAAK,CAAC,CACzCC,GAAG,CAAEP,IAAI,KAAM;IAAEE,IAAI,EAAEF,IAAI,CAACE,IAAI;IAAEM,IAAI,EAAER,IAAI,CAACQ;EAAK,CAAC,CAAC,CAAC,EAC1D,CAACpB,gBAAgB,CACnB,CAAC;EAED,MAAMqB,0BAA0B,GAAGlD,WAAW,CAC3CmD,CAAoD,IAAK;IACxD,MAAM;MAAEC,QAAQ;MAAEC,YAAY;MAAEC,cAAc;MAAEC;IAAa,CAAC,GAC5DJ,CAAC,CAACK,WAAW;IACf,MAAMC,QAAQ,GAAGnB,uBAAuB,CAACH,OAAO,CAACuB,GAAG,CAACN,QAAQ,CAAC;IAC9DK,QAAQ,GAAG;MACTd,IAAI,EAAEU,YAAY;MAClBM,SAAS,EAAE;QAAEC,KAAK,EAAEN,cAAc;QAAEO,GAAG,EAAEN;MAAa;IACxD,CAAC,CAAC;EACJ,CAAC,EACD,EACF,CAAC;EAED,MAAMO,eAAe,GAAG9D,WAAW,CAChCmD,CAAuC,IAAK;IAC3C,MAAM;MAAEY;IAAI,CAAC,GAAGZ,CAAC,CAACK,WAAW;IAC7BzC,WAAW,GAAG;MAAEgD;IAAI,CAAC,CAAC;EACxB,CAAC,EACD,CAAChD,WAAW,CACd,CAAC;EAED,MAAMiD,mBAAmB,GAAGhE,WAAW,CACpCmD,CAA2C,IAAK;IAC/C,MAAM;MAAEY;IAAI,CAAC,GAAGZ,CAAC,CAACK,WAAW;IAC7BxC,eAAe,GAAG;MAAE+C;IAAI,CAAC,CAAC;EAC5B,CAAC,EACD,CAAC/C,eAAe,CAClB,CAAC;EAED,MAAMiD,uBAAuB,GAAGjE,WAAW,CACxCmD,CAA+C,IAAK;IACnD,MAAM;MAAEe,KAAK;MAAEC,OAAO;MAAExB;IAAK,CAAC,GAAGQ,CAAC,CAACK,WAAW;IAC9CvC,mBAAmB,GAAG;MAAEiD,KAAK;MAAEC,OAAO;MAAExB;IAAK,CAAC,CAAC;EACjD,CAAC,EACD,CAAC1B,mBAAmB,CACtB,CAAC;EAED,MAAMmD,kBAAkB,GAAGpE,WAAW,CACnCmD,CAA0C,IAAK;IAC9C,MAAM;MAAEY,GAAG;MAAEpB;IAAK,CAAC,GAAGQ,CAAC,CAACK,WAAW;IACnCtC,cAAc,GAAG;MAAE6C,GAAG;MAAEpB;IAAK,CAAC,CAAC;EACjC,CAAC,EACD,CAACzB,cAAc,CACjB,CAAC;EAED,MAAMmD,mBAAmB,GAAGrE,WAAW,CACpCmD,CAA2C,IAAK;IAC/C,MAAM;MAAEY,GAAG;MAAEpB;IAAK,CAAC,GAAGQ,CAAC,CAACK,WAAW;IACnCrC,eAAe,GAAG;MAAE4C,GAAG;MAAEpB;IAAK,CAAC,CAAC;EAClC,CAAC,EACD,CAACxB,eAAe,CAClB,CAAC;EAED,MAAMmD,WAAW,GAAG;IAClB1D,QAAQ;IACRC,aAAa,EAAEuB,eAAe;IAC9BrB,WAAW,EAAE+C,eAAe;IAC5B9C,eAAe,EAAEgD,mBAAmB;IACpC/C,mBAAmB,EAAEgD,uBAAuB;IAC5C/C,cAAc,EAAEA,cAAc,GAAGkD,kBAAkB,GAAGG,SAAS;IAC/DpD,eAAe,EAAEA,eAAe,GAAGkD,mBAAmB,GAAGE,SAAS;IAClEnD,iBAAiB,EAAEJ,eAAe,IAAI,IAAI,KAAKI,iBAAiB,IAAI,IAAI,CAAC;IACzEC,UAAU;IACVC,SAAS,EAAEe,mBAAmB;IAC9Bd,gBAAgB;IAChBC,qBAAqB;IACrBC,mBAAmB;IACnBE,kBAAkB;IAClBC,cAAc;IACd4C,KAAK,EAAE1D,cAAc;IACrBe,gBAAgB,EAAEgB,sBAAsB;IACxC4B,sBAAsB,EAAEvB,0BAA0B;IAClDpB,cAAc;IACdC,oBAAoB;IACpB,GAAGC;EACL,CAAC;EAED,IAAIN,MAAM,KAAK,QAAQ,EAAE;IACvB,oBAAOnB,IAAA,CAACH,+BAA+B;MAAA,GAAKkE;IAAW,CAAG,CAAC;EAC7D;EAEA,oBAAO/D,IAAA,CAACJ,mCAAmC;IAAA,GAAKmE;EAAW,CAAG,CAAC;AACjE,CAAC;AAED,eAAe3D,oBAAoB","ignoreList":[]} diff --git a/lib/module/normalizeMarkdownStyle.js b/lib/module/normalizeMarkdownStyle.js new file mode 100644 index 00000000..99d466c7 --- /dev/null +++ b/lib/module/normalizeMarkdownStyle.js @@ -0,0 +1,325 @@ +"use strict"; + +import { Platform } from 'react-native'; +import { isStyleEqual, normalizeColor, mergeSubStyle } from "./styleUtils.js"; +const getSystemFont = () => Platform.select({ + ios: 'System', + android: 'sans-serif', + web: 'system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif', + default: 'sans-serif' +}); +const getMonospaceFont = () => Platform.select({ + ios: 'Menlo', + android: 'monospace', + web: 'ui-monospace, "Cascadia Code", "Source Code Pro", Menlo, Consolas, "DejaVu Sans Mono", monospace', + default: 'monospace' +}); +const defaultTextColor = normalizeColor('#1F2937'); +const defaultHeadingColor = normalizeColor('#111827'); + +// Explicit type annotation needed: Object.freeze breaks contextual typing, so +// TypeScript widens literal 'auto' to `string` instead of `BlockTextAlign`. +const baseHeader = { + fontFamily: getSystemFont(), + fontWeight: '', + marginTop: 0, + marginBottom: 8, + textAlign: 'auto' +}; +const DEFAULT_NORMALIZED_STYLE = Object.freeze({ + paragraph: { + fontSize: 16, + fontFamily: getSystemFont(), + fontWeight: '', + color: defaultTextColor, + lineHeight: Platform.select({ + ios: 24, + android: 26, + default: 26 + }), + marginTop: 0, + marginBottom: 16, + textAlign: 'auto' + }, + h1: { + ...baseHeader, + fontSize: 30, + color: defaultHeadingColor, + lineHeight: Platform.select({ + ios: 36, + android: 38, + default: 38 + }) + }, + h2: { + ...baseHeader, + fontSize: 24, + color: defaultHeadingColor, + lineHeight: Platform.select({ + ios: 30, + android: 32, + default: 32 + }) + }, + h3: { + ...baseHeader, + fontSize: 20, + color: defaultHeadingColor, + lineHeight: Platform.select({ + ios: 26, + android: 28, + default: 28 + }) + }, + h4: { + ...baseHeader, + fontSize: 18, + color: defaultHeadingColor, + lineHeight: Platform.select({ + ios: 24, + android: 26, + default: 26 + }) + }, + h5: { + ...baseHeader, + fontSize: 16, + color: normalizeColor('#374151'), + lineHeight: Platform.select({ + ios: 22, + android: 24, + default: 24 + }) + }, + h6: { + ...baseHeader, + fontSize: 14, + color: normalizeColor('#4B5563'), + lineHeight: Platform.select({ + ios: 20, + android: 22, + default: 22 + }) + }, + blockquote: { + fontSize: 16, + fontFamily: getSystemFont(), + fontWeight: '', + color: normalizeColor('#4B5563'), + lineHeight: Platform.select({ + ios: 24, + android: 26, + default: 26 + }), + marginTop: 0, + marginBottom: 16, + borderColor: normalizeColor('#D1D5DB'), + borderWidth: 3, + gapWidth: 16, + backgroundColor: normalizeColor('#F9FAFB') + }, + list: { + fontSize: 16, + fontFamily: getSystemFont(), + fontWeight: '', + color: defaultTextColor, + lineHeight: Platform.select({ + ios: 22, + android: 26, + default: 26 + }), + marginTop: 0, + marginBottom: 16, + bulletColor: normalizeColor('#6B7280'), + bulletSize: 6, + markerMinWidth: 0, + markerColor: normalizeColor('#6B7280'), + markerFontWeight: '500', + gapWidth: 12, + marginLeft: 24 + }, + codeBlock: { + fontSize: 14, + fontFamily: getMonospaceFont(), + fontWeight: '', + color: normalizeColor('#F3F4F6'), + lineHeight: Platform.select({ + ios: 20, + android: 22, + default: 22 + }), + marginTop: 0, + marginBottom: 16, + backgroundColor: normalizeColor('#1F2937'), + borderColor: normalizeColor('#374151'), + borderRadius: 8, + borderWidth: 1, + padding: 16 + }, + link: { + fontFamily: '', + color: normalizeColor('#2563EB'), + underline: true + }, + strong: { + fontFamily: '', + fontWeight: 'bold', + color: undefined + }, + em: { + fontFamily: '', + fontStyle: 'italic', + color: undefined + }, + strikethrough: { + color: normalizeColor('#9CA3AF') + }, + underline: { + color: defaultTextColor + }, + code: { + // Native uses '' (inherit); web needs an explicit monospace stack so inline + // code doesn't fall back to the browser's default proportional font. + fontFamily: Platform.select({ + web: getMonospaceFont(), + default: '' + }), + fontSize: 0, + color: normalizeColor('#E01E5A'), + backgroundColor: normalizeColor('#FDF2F4'), + borderColor: normalizeColor('#F8D7DA') + }, + image: { + height: 200, + borderRadius: 8, + marginTop: 0, + marginBottom: 16 + }, + inlineImage: { + size: 20 + }, + thematicBreak: { + color: normalizeColor('#E5E7EB'), + height: 1, + marginTop: 24, + marginBottom: 24 + }, + table: { + fontSize: 14, + fontFamily: getSystemFont(), + fontWeight: '', + color: defaultTextColor, + marginTop: 0, + marginBottom: 16, + lineHeight: Platform.select({ + ios: 20, + android: 22, + default: 22 + }), + headerFontFamily: '', + headerBackgroundColor: normalizeColor('#F3F4F6'), + headerTextColor: normalizeColor('#111827'), + rowEvenBackgroundColor: normalizeColor('#FFFFFF'), + rowOddBackgroundColor: normalizeColor('#F9FAFB'), + borderColor: normalizeColor('#E5E7EB'), + borderWidth: 1, + borderRadius: 6, + cellPaddingHorizontal: 12, + cellPaddingVertical: 8 + }, + math: { + fontSize: 20, + color: defaultTextColor, + backgroundColor: normalizeColor('#F3F4F6'), + padding: 12, + marginTop: 0, + marginBottom: 16, + textAlign: 'center' + }, + inlineMath: { + color: defaultTextColor + }, + taskList: { + checkedColor: Platform.select({ + ios: normalizeColor('#007AFF'), + android: normalizeColor('#2196F3'), + default: normalizeColor('#007AFF') + }), + borderColor: normalizeColor('#9E9E9E'), + checkboxSize: 14, + checkboxBorderRadius: 3, + checkmarkColor: normalizeColor('#FFFFFF'), + checkedTextColor: normalizeColor('#000000'), + checkedStrikethrough: false + }, + spoiler: { + color: normalizeColor('#374151'), + particles: { + density: 8, + speed: 20 + }, + solid: { + borderRadius: 4 + } + }, + mention: { + color: normalizeColor('#1D4ED8'), + backgroundColor: normalizeColor('#DBEAFE'), + borderColor: normalizeColor('#BFDBFE'), + borderWidth: 0, + borderRadius: 999, + paddingHorizontal: 6, + paddingVertical: 1, + fontFamily: '', + fontWeight: '500', + fontSize: 0, + pressedOpacity: 0.6 + }, + citation: { + color: normalizeColor('#2563EB'), + fontSizeMultiplier: 0.7, + baselineOffsetPx: 0, + fontWeight: '', + underline: false, + backgroundColor: 'transparent', + paddingHorizontal: 0, + paddingVertical: 0, + borderColor: 'transparent', + borderWidth: 0, + borderRadius: 999 + } +}); +const refCache = new WeakMap(); +const structuralCache = []; +const LRU_MAX = 8; +const styleReferenceKeys = Object.keys(DEFAULT_NORMALIZED_STYLE); +export const normalizeMarkdownStyle = style => { + if (!style || Object.keys(style).length === 0) return DEFAULT_NORMALIZED_STYLE; + const refHit = refCache.get(style); + if (refHit) return refHit; + const structIdx = structuralCache.findIndex(e => isStyleEqual(e.style, style, styleReferenceKeys)); + if (structIdx !== -1) { + const entry = structuralCache.splice(structIdx, 1)[0]; + structuralCache.unshift(entry); + refCache.set(style, entry.result); + return entry.result; + } + const result = {}; + Object.keys(DEFAULT_NORMALIZED_STYLE).forEach(key => { + const userValue = style[key]; + result[key] = mergeSubStyle(DEFAULT_NORMALIZED_STYLE[key], userValue); + }); + if (style.taskList?.checkboxSize === undefined) { + const listSize = result.list.fontSize; + result.taskList.checkboxSize = Math.round(listSize * 0.9); + } + const finalResult = Object.freeze(result); + refCache.set(style, finalResult); + structuralCache.unshift({ + style, + result: finalResult + }); + if (structuralCache.length > LRU_MAX) structuralCache.pop(); + return finalResult; +}; +//# sourceMappingURL=normalizeMarkdownStyle.js.map \ No newline at end of file diff --git a/lib/module/normalizeMarkdownStyle.js.map b/lib/module/normalizeMarkdownStyle.js.map new file mode 100644 index 00000000..73f74c72 --- /dev/null +++ b/lib/module/normalizeMarkdownStyle.js.map @@ -0,0 +1 @@ +{"version":3,"names":["Platform","isStyleEqual","normalizeColor","mergeSubStyle","getSystemFont","select","ios","android","web","default","getMonospaceFont","defaultTextColor","defaultHeadingColor","baseHeader","fontFamily","fontWeight","marginTop","marginBottom","textAlign","DEFAULT_NORMALIZED_STYLE","Object","freeze","paragraph","fontSize","color","lineHeight","h1","h2","h3","h4","h5","h6","blockquote","borderColor","borderWidth","gapWidth","backgroundColor","list","bulletColor","bulletSize","markerMinWidth","markerColor","markerFontWeight","marginLeft","codeBlock","borderRadius","padding","link","underline","strong","undefined","em","fontStyle","strikethrough","code","image","height","inlineImage","size","thematicBreak","table","headerFontFamily","headerBackgroundColor","headerTextColor","rowEvenBackgroundColor","rowOddBackgroundColor","cellPaddingHorizontal","cellPaddingVertical","math","inlineMath","taskList","checkedColor","checkboxSize","checkboxBorderRadius","checkmarkColor","checkedTextColor","checkedStrikethrough","spoiler","particles","density","speed","solid","mention","paddingHorizontal","paddingVertical","pressedOpacity","citation","fontSizeMultiplier","baselineOffsetPx","refCache","WeakMap","structuralCache","LRU_MAX","styleReferenceKeys","keys","normalizeMarkdownStyle","style","length","refHit","get","structIdx","findIndex","e","entry","splice","unshift","set","result","forEach","key","userValue","listSize","Math","round","finalResult","pop"],"sourceRoot":"../../src","sources":["normalizeMarkdownStyle.ts"],"mappings":";;AAAA,SAASA,QAAQ,QAAQ,cAAc;AAOvC,SAASC,YAAY,EAAEC,cAAc,EAAEC,aAAa,QAAQ,iBAAc;AAE1E,MAAMC,aAAa,GAAGA,CAAA,KACpBJ,QAAQ,CAACK,MAAM,CAAC;EACdC,GAAG,EAAE,QAAQ;EACbC,OAAO,EAAE,YAAY;EACrBC,GAAG,EAAE,8EAA8E;EACnFC,OAAO,EAAE;AACX,CAAC,CAAE;AAEL,MAAMC,gBAAgB,GAAGA,CAAA,KACvBV,QAAQ,CAACK,MAAM,CAAC;EACdC,GAAG,EAAE,OAAO;EACZC,OAAO,EAAE,WAAW;EACpBC,GAAG,EAAE,kGAAkG;EACvGC,OAAO,EAAE;AACX,CAAC,CAAE;AAEL,MAAME,gBAAgB,GAAGT,cAAc,CAAC,SAAS,CAAE;AACnD,MAAMU,mBAAmB,GAAGV,cAAc,CAAC,SAAS,CAAE;;AAEtD;AACA;AACA,MAAMW,UAML,GAAG;EACFC,UAAU,EAAEV,aAAa,CAAC,CAAC;EAC3BW,UAAU,EAAE,EAAE;EACdC,SAAS,EAAE,CAAC;EACZC,YAAY,EAAE,CAAC;EACfC,SAAS,EAAE;AACb,CAAC;AAED,MAAMC,wBAAwB,GAAGC,MAAM,CAACC,MAAM,CAAC;EAC7CC,SAAS,EAAE;IACTC,QAAQ,EAAE,EAAE;IACZT,UAAU,EAAEV,aAAa,CAAC,CAAC;IAC3BW,UAAU,EAAE,EAAE;IACdS,KAAK,EAAEb,gBAAgB;IACvBc,UAAU,EAAEzB,QAAQ,CAACK,MAAM,CAAC;MAAEC,GAAG,EAAE,EAAE;MAAEC,OAAO,EAAE,EAAE;MAAEE,OAAO,EAAE;IAAG,CAAC,CAAE;IACnEO,SAAS,EAAE,CAAC;IACZC,YAAY,EAAE,EAAE;IAChBC,SAAS,EAAE;EACb,CAAC;EACDQ,EAAE,EAAE;IACF,GAAGb,UAAU;IACbU,QAAQ,EAAE,EAAE;IACZC,KAAK,EAAEZ,mBAAmB;IAC1Ba,UAAU,EAAEzB,QAAQ,CAACK,MAAM,CAAC;MAAEC,GAAG,EAAE,EAAE;MAAEC,OAAO,EAAE,EAAE;MAAEE,OAAO,EAAE;IAAG,CAAC;EACnE,CAAC;EACDkB,EAAE,EAAE;IACF,GAAGd,UAAU;IACbU,QAAQ,EAAE,EAAE;IACZC,KAAK,EAAEZ,mBAAmB;IAC1Ba,UAAU,EAAEzB,QAAQ,CAACK,MAAM,CAAC;MAAEC,GAAG,EAAE,EAAE;MAAEC,OAAO,EAAE,EAAE;MAAEE,OAAO,EAAE;IAAG,CAAC;EACnE,CAAC;EACDmB,EAAE,EAAE;IACF,GAAGf,UAAU;IACbU,QAAQ,EAAE,EAAE;IACZC,KAAK,EAAEZ,mBAAmB;IAC1Ba,UAAU,EAAEzB,QAAQ,CAACK,MAAM,CAAC;MAAEC,GAAG,EAAE,EAAE;MAAEC,OAAO,EAAE,EAAE;MAAEE,OAAO,EAAE;IAAG,CAAC;EACnE,CAAC;EACDoB,EAAE,EAAE;IACF,GAAGhB,UAAU;IACbU,QAAQ,EAAE,EAAE;IACZC,KAAK,EAAEZ,mBAAmB;IAC1Ba,UAAU,EAAEzB,QAAQ,CAACK,MAAM,CAAC;MAAEC,GAAG,EAAE,EAAE;MAAEC,OAAO,EAAE,EAAE;MAAEE,OAAO,EAAE;IAAG,CAAC;EACnE,CAAC;EACDqB,EAAE,EAAE;IACF,GAAGjB,UAAU;IACbU,QAAQ,EAAE,EAAE;IACZC,KAAK,EAAEtB,cAAc,CAAC,SAAS,CAAE;IACjCuB,UAAU,EAAEzB,QAAQ,CAACK,MAAM,CAAC;MAAEC,GAAG,EAAE,EAAE;MAAEC,OAAO,EAAE,EAAE;MAAEE,OAAO,EAAE;IAAG,CAAC;EACnE,CAAC;EACDsB,EAAE,EAAE;IACF,GAAGlB,UAAU;IACbU,QAAQ,EAAE,EAAE;IACZC,KAAK,EAAEtB,cAAc,CAAC,SAAS,CAAE;IACjCuB,UAAU,EAAEzB,QAAQ,CAACK,MAAM,CAAC;MAAEC,GAAG,EAAE,EAAE;MAAEC,OAAO,EAAE,EAAE;MAAEE,OAAO,EAAE;IAAG,CAAC;EACnE,CAAC;EACDuB,UAAU,EAAE;IACVT,QAAQ,EAAE,EAAE;IACZT,UAAU,EAAEV,aAAa,CAAC,CAAC;IAC3BW,UAAU,EAAE,EAAE;IACdS,KAAK,EAAEtB,cAAc,CAAC,SAAS,CAAE;IACjCuB,UAAU,EAAEzB,QAAQ,CAACK,MAAM,CAAC;MAAEC,GAAG,EAAE,EAAE;MAAEC,OAAO,EAAE,EAAE;MAAEE,OAAO,EAAE;IAAG,CAAC,CAAE;IACnEO,SAAS,EAAE,CAAC;IACZC,YAAY,EAAE,EAAE;IAChBgB,WAAW,EAAE/B,cAAc,CAAC,SAAS,CAAE;IACvCgC,WAAW,EAAE,CAAC;IACdC,QAAQ,EAAE,EAAE;IACZC,eAAe,EAAElC,cAAc,CAAC,SAAS;EAC3C,CAAC;EACDmC,IAAI,EAAE;IACJd,QAAQ,EAAE,EAAE;IACZT,UAAU,EAAEV,aAAa,CAAC,CAAC;IAC3BW,UAAU,EAAE,EAAE;IACdS,KAAK,EAAEb,gBAAgB;IACvBc,UAAU,EAAEzB,QAAQ,CAACK,MAAM,CAAC;MAAEC,GAAG,EAAE,EAAE;MAAEC,OAAO,EAAE,EAAE;MAAEE,OAAO,EAAE;IAAG,CAAC,CAAE;IACnEO,SAAS,EAAE,CAAC;IACZC,YAAY,EAAE,EAAE;IAChBqB,WAAW,EAAEpC,cAAc,CAAC,SAAS,CAAE;IACvCqC,UAAU,EAAE,CAAC;IACbC,cAAc,EAAE,CAAC;IACjBC,WAAW,EAAEvC,cAAc,CAAC,SAAS,CAAE;IACvCwC,gBAAgB,EAAE,KAAK;IACvBP,QAAQ,EAAE,EAAE;IACZQ,UAAU,EAAE;EACd,CAAC;EACDC,SAAS,EAAE;IACTrB,QAAQ,EAAE,EAAE;IACZT,UAAU,EAAEJ,gBAAgB,CAAC,CAAC;IAC9BK,UAAU,EAAE,EAAE;IACdS,KAAK,EAAEtB,cAAc,CAAC,SAAS,CAAE;IACjCuB,UAAU,EAAEzB,QAAQ,CAACK,MAAM,CAAC;MAAEC,GAAG,EAAE,EAAE;MAAEC,OAAO,EAAE,EAAE;MAAEE,OAAO,EAAE;IAAG,CAAC,CAAE;IACnEO,SAAS,EAAE,CAAC;IACZC,YAAY,EAAE,EAAE;IAChBmB,eAAe,EAAElC,cAAc,CAAC,SAAS,CAAE;IAC3C+B,WAAW,EAAE/B,cAAc,CAAC,SAAS,CAAE;IACvC2C,YAAY,EAAE,CAAC;IACfX,WAAW,EAAE,CAAC;IACdY,OAAO,EAAE;EACX,CAAC;EACDC,IAAI,EAAE;IAAEjC,UAAU,EAAE,EAAE;IAAEU,KAAK,EAAEtB,cAAc,CAAC,SAAS,CAAE;IAAE8C,SAAS,EAAE;EAAK,CAAC;EAC5EC,MAAM,EAAE;IAAEnC,UAAU,EAAE,EAAE;IAAEC,UAAU,EAAE,MAAM;IAAES,KAAK,EAAE0B;EAAU,CAAC;EAChEC,EAAE,EAAE;IACFrC,UAAU,EAAE,EAAE;IACdsC,SAAS,EAAE,QAA6B;IACxC5B,KAAK,EAAE0B;EACT,CAAC;EACDG,aAAa,EAAE;IAAE7B,KAAK,EAAEtB,cAAc,CAAC,SAAS;EAAG,CAAC;EACpD8C,SAAS,EAAE;IAAExB,KAAK,EAAEb;EAAiB,CAAC;EACtC2C,IAAI,EAAE;IACJ;IACA;IACAxC,UAAU,EAAEd,QAAQ,CAACK,MAAM,CAAC;MAAEG,GAAG,EAAEE,gBAAgB,CAAC,CAAC;MAAED,OAAO,EAAE;IAAG,CAAC,CAAE;IACtEc,QAAQ,EAAE,CAAC;IACXC,KAAK,EAAEtB,cAAc,CAAC,SAAS,CAAE;IACjCkC,eAAe,EAAElC,cAAc,CAAC,SAAS,CAAE;IAC3C+B,WAAW,EAAE/B,cAAc,CAAC,SAAS;EACvC,CAAC;EACDqD,KAAK,EAAE;IAAEC,MAAM,EAAE,GAAG;IAAEX,YAAY,EAAE,CAAC;IAAE7B,SAAS,EAAE,CAAC;IAAEC,YAAY,EAAE;EAAG,CAAC;EACvEwC,WAAW,EAAE;IAAEC,IAAI,EAAE;EAAG,CAAC;EACzBC,aAAa,EAAE;IACbnC,KAAK,EAAEtB,cAAc,CAAC,SAAS,CAAE;IACjCsD,MAAM,EAAE,CAAC;IACTxC,SAAS,EAAE,EAAE;IACbC,YAAY,EAAE;EAChB,CAAC;EACD2C,KAAK,EAAE;IACLrC,QAAQ,EAAE,EAAE;IACZT,UAAU,EAAEV,aAAa,CAAC,CAAC;IAC3BW,UAAU,EAAE,EAAE;IACdS,KAAK,EAAEb,gBAAgB;IACvBK,SAAS,EAAE,CAAC;IACZC,YAAY,EAAE,EAAE;IAChBQ,UAAU,EAAEzB,QAAQ,CAACK,MAAM,CAAC;MAAEC,GAAG,EAAE,EAAE;MAAEC,OAAO,EAAE,EAAE;MAAEE,OAAO,EAAE;IAAG,CAAC,CAAE;IACnEoD,gBAAgB,EAAE,EAAE;IACpBC,qBAAqB,EAAE5D,cAAc,CAAC,SAAS,CAAE;IACjD6D,eAAe,EAAE7D,cAAc,CAAC,SAAS,CAAE;IAC3C8D,sBAAsB,EAAE9D,cAAc,CAAC,SAAS,CAAE;IAClD+D,qBAAqB,EAAE/D,cAAc,CAAC,SAAS,CAAE;IACjD+B,WAAW,EAAE/B,cAAc,CAAC,SAAS,CAAE;IACvCgC,WAAW,EAAE,CAAC;IACdW,YAAY,EAAE,CAAC;IACfqB,qBAAqB,EAAE,EAAE;IACzBC,mBAAmB,EAAE;EACvB,CAAC;EACDC,IAAI,EAAE;IACJ7C,QAAQ,EAAE,EAAE;IACZC,KAAK,EAAEb,gBAAgB;IACvByB,eAAe,EAAElC,cAAc,CAAC,SAAS,CAAE;IAC3C4C,OAAO,EAAE,EAAE;IACX9B,SAAS,EAAE,CAAC;IACZC,YAAY,EAAE,EAAE;IAChBC,SAAS,EAAE;EACb,CAAC;EACDmD,UAAU,EAAE;IAAE7C,KAAK,EAAEb;EAAiB,CAAC;EACvC2D,QAAQ,EAAE;IACRC,YAAY,EAAEvE,QAAQ,CAACK,MAAM,CAAC;MAC5BC,GAAG,EAAEJ,cAAc,CAAC,SAAS,CAAE;MAC/BK,OAAO,EAAEL,cAAc,CAAC,SAAS,CAAE;MACnCO,OAAO,EAAEP,cAAc,CAAC,SAAS;IACnC,CAAC,CAAE;IACH+B,WAAW,EAAE/B,cAAc,CAAC,SAAS,CAAE;IACvCsE,YAAY,EAAE,EAAE;IAChBC,oBAAoB,EAAE,CAAC;IACvBC,cAAc,EAAExE,cAAc,CAAC,SAAS,CAAE;IAC1CyE,gBAAgB,EAAEzE,cAAc,CAAC,SAAS,CAAE;IAC5C0E,oBAAoB,EAAE;EACxB,CAAC;EACDC,OAAO,EAAE;IACPrD,KAAK,EAAEtB,cAAc,CAAC,SAAS,CAAE;IACjC4E,SAAS,EAAE;MAAEC,OAAO,EAAE,CAAC;MAAEC,KAAK,EAAE;IAAG,CAAC;IACpCC,KAAK,EAAE;MAAEpC,YAAY,EAAE;IAAE;EAC3B,CAAC;EACDqC,OAAO,EAAE;IACP1D,KAAK,EAAEtB,cAAc,CAAC,SAAS,CAAE;IACjCkC,eAAe,EAAElC,cAAc,CAAC,SAAS,CAAE;IAC3C+B,WAAW,EAAE/B,cAAc,CAAC,SAAS,CAAE;IACvCgC,WAAW,EAAE,CAAC;IACdW,YAAY,EAAE,GAAG;IACjBsC,iBAAiB,EAAE,CAAC;IACpBC,eAAe,EAAE,CAAC;IAClBtE,UAAU,EAAE,EAAE;IACdC,UAAU,EAAE,KAAK;IACjBQ,QAAQ,EAAE,CAAC;IACX8D,cAAc,EAAE;EAClB,CAAC;EACDC,QAAQ,EAAE;IACR9D,KAAK,EAAEtB,cAAc,CAAC,SAAS,CAAE;IACjCqF,kBAAkB,EAAE,GAAG;IACvBC,gBAAgB,EAAE,CAAC;IACnBzE,UAAU,EAAE,EAAE;IACdiC,SAAS,EAAE,KAAK;IAChBZ,eAAe,EAAE,aAAa;IAC9B+C,iBAAiB,EAAE,CAAC;IACpBC,eAAe,EAAE,CAAC;IAClBnD,WAAW,EAAE,aAAa;IAC1BC,WAAW,EAAE,CAAC;IACdW,YAAY,EAAE;EAChB;AACF,CAAC,CAA0B;AAE3B,MAAM4C,QAAQ,GAAG,IAAIC,OAAO,CAAuC,CAAC;AACpE,MAAMC,eAGH,GAAG,EAAE;AACR,MAAMC,OAAO,GAAG,CAAC;AAEjB,MAAMC,kBAAkB,GAAGzE,MAAM,CAAC0E,IAAI,CAAC3E,wBAAwB,CAAC;AAEhE,OAAO,MAAM4E,sBAAsB,GACjCC,KAAoB,IACM;EAC1B,IAAI,CAACA,KAAK,IAAI5E,MAAM,CAAC0E,IAAI,CAACE,KAAK,CAAC,CAACC,MAAM,KAAK,CAAC,EAC3C,OAAO9E,wBAAwB;EAEjC,MAAM+E,MAAM,GAAGT,QAAQ,CAACU,GAAG,CAACH,KAAK,CAAC;EAClC,IAAIE,MAAM,EAAE,OAAOA,MAAM;EAEzB,MAAME,SAAS,GAAGT,eAAe,CAACU,SAAS,CAAEC,CAAC,IAC5CrG,YAAY,CAACqG,CAAC,CAACN,KAAK,EAAEA,KAAK,EAAEH,kBAAkB,CACjD,CAAC;EACD,IAAIO,SAAS,KAAK,CAAC,CAAC,EAAE;IACpB,MAAMG,KAAK,GAAGZ,eAAe,CAACa,MAAM,CAACJ,SAAS,EAAE,CAAC,CAAC,CAAC,CAAC,CAAE;IACtDT,eAAe,CAACc,OAAO,CAACF,KAAK,CAAC;IAC9Bd,QAAQ,CAACiB,GAAG,CAACV,KAAK,EAAEO,KAAK,CAACI,MAAM,CAAC;IACjC,OAAOJ,KAAK,CAACI,MAAM;EACrB;EAEA,MAAMA,MAA+B,GAAG,CAAC,CAAC;EAExCvF,MAAM,CAAC0E,IAAI,CAAC3E,wBAAwB,CAAC,CACrCyF,OAAO,CAAEC,GAAG,IAAK;IACjB,MAAMC,SAAS,GAAGd,KAAK,CAACa,GAAG,CAEd;IACbF,MAAM,CAACE,GAAG,CAAC,GAAG1G,aAAa,CACzBgB,wBAAwB,CAAC0F,GAAG,CAAC,EAC7BC,SACF,CAAC;EACH,CAAC,CAAC;EAEF,IAAId,KAAK,CAAC1B,QAAQ,EAAEE,YAAY,KAAKtB,SAAS,EAAE;IAC9C,MAAM6D,QAAQ,GAAIJ,MAAM,CAACtE,IAAI,CAA0Bd,QAAQ;IAC9DoF,MAAM,CAACrC,QAAQ,CAA8BE,YAAY,GAAGwC,IAAI,CAACC,KAAK,CACrEF,QAAQ,GAAG,GACb,CAAC;EACH;EAEA,MAAMG,WAAW,GAAG9F,MAAM,CAACC,MAAM,CAACsF,MAAM,CAAqC;EAC7ElB,QAAQ,CAACiB,GAAG,CAACV,KAAK,EAAEkB,WAAW,CAAC;EAChCvB,eAAe,CAACc,OAAO,CAAC;IAAET,KAAK;IAAEW,MAAM,EAAEO;EAAY,CAAC,CAAC;EACvD,IAAIvB,eAAe,CAACM,MAAM,GAAGL,OAAO,EAAED,eAAe,CAACwB,GAAG,CAAC,CAAC;EAE3D,OAAOD,WAAW;AACpB,CAAC","ignoreList":[]} diff --git a/lib/module/normalizeMarkdownStyle.web.js b/lib/module/normalizeMarkdownStyle.web.js new file mode 100644 index 00000000..eb198f17 --- /dev/null +++ b/lib/module/normalizeMarkdownStyle.web.js @@ -0,0 +1,259 @@ +"use strict"; + +import { isStyleEqual, mergeSubStyle } from "./styleUtils.js"; +const SYSTEM_FONT = 'system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif'; +const MONOSPACE_FONT = 'ui-monospace, "Cascadia Code", "Source Code Pro", Menlo, Consolas, "DejaVu Sans Mono", monospace'; +const defaultTextColor = '#1F2937'; +const defaultHeadingColor = '#111827'; +const baseHeader = { + fontFamily: SYSTEM_FONT, + fontWeight: '', + marginTop: 0, + marginBottom: 8, + textAlign: 'auto' +}; +const DEFAULT_NORMALIZED_STYLE = Object.freeze({ + paragraph: { + fontSize: 16, + fontFamily: SYSTEM_FONT, + fontWeight: '', + color: defaultTextColor, + lineHeight: 26, + marginTop: 0, + marginBottom: 16, + textAlign: 'auto' + }, + h1: { + ...baseHeader, + fontSize: 30, + color: defaultHeadingColor, + lineHeight: 38 + }, + h2: { + ...baseHeader, + fontSize: 24, + color: defaultHeadingColor, + lineHeight: 32 + }, + h3: { + ...baseHeader, + fontSize: 20, + color: defaultHeadingColor, + lineHeight: 28 + }, + h4: { + ...baseHeader, + fontSize: 18, + color: defaultHeadingColor, + lineHeight: 26 + }, + h5: { + ...baseHeader, + fontSize: 16, + color: '#374151', + lineHeight: 24 + }, + h6: { + ...baseHeader, + fontSize: 14, + color: '#4B5563', + lineHeight: 22 + }, + blockquote: { + fontSize: 16, + fontFamily: SYSTEM_FONT, + fontWeight: '', + color: '#4B5563', + lineHeight: 26, + marginTop: 0, + marginBottom: 16, + borderColor: '#D1D5DB', + borderWidth: 3, + gapWidth: 16, + backgroundColor: '#F9FAFB' + }, + list: { + fontSize: 16, + fontFamily: SYSTEM_FONT, + fontWeight: '', + color: defaultTextColor, + lineHeight: 26, + marginTop: 0, + marginBottom: 16, + bulletColor: '#6B7280', + bulletSize: 6, + markerMinWidth: 0, + markerColor: '#6B7280', + markerFontWeight: '500', + gapWidth: 12, + marginLeft: 24 + }, + codeBlock: { + fontSize: 14, + fontFamily: MONOSPACE_FONT, + fontWeight: '', + color: '#F3F4F6', + lineHeight: 22, + marginTop: 0, + marginBottom: 16, + backgroundColor: '#1F2937', + borderColor: '#374151', + borderRadius: 8, + borderWidth: 1, + padding: 16 + }, + link: { + fontFamily: '', + color: '#2563EB', + underline: true + }, + strong: { + fontFamily: '', + fontWeight: 'bold', + color: undefined + }, + em: { + fontFamily: '', + fontStyle: 'italic', + color: undefined + }, + strikethrough: { + color: '#9CA3AF' + }, + underline: { + color: defaultTextColor + }, + code: { + fontFamily: MONOSPACE_FONT, + fontSize: 0, + color: '#E01E5A', + backgroundColor: '#FDF2F4', + borderColor: '#F8D7DA' + }, + image: { + height: 200, + borderRadius: 8, + marginTop: 0, + marginBottom: 16 + }, + inlineImage: { + size: 20 + }, + thematicBreak: { + color: '#E5E7EB', + height: 1, + marginTop: 24, + marginBottom: 24 + }, + table: { + fontSize: 14, + fontFamily: SYSTEM_FONT, + fontWeight: '', + color: defaultTextColor, + marginTop: 0, + marginBottom: 16, + lineHeight: 22, + headerFontFamily: '', + headerBackgroundColor: '#F3F4F6', + headerTextColor: '#111827', + rowEvenBackgroundColor: '#FFFFFF', + rowOddBackgroundColor: '#F9FAFB', + borderColor: '#E5E7EB', + borderWidth: 1, + borderRadius: 6, + cellPaddingHorizontal: 12, + cellPaddingVertical: 8 + }, + math: { + fontSize: 20, + color: defaultTextColor, + backgroundColor: '#F3F4F6', + padding: 12, + marginTop: 0, + marginBottom: 16, + textAlign: 'center' + }, + inlineMath: { + color: defaultTextColor + }, + taskList: { + checkedColor: '#007AFF', + borderColor: '#9E9E9E', + checkboxSize: 14, + checkboxBorderRadius: 3, + checkmarkColor: '#FFFFFF', + checkedTextColor: '#000000', + checkedStrikethrough: false + }, + // Spoiler rendering is not supported on web yet — defaults kept for type compatibility. + spoiler: { + color: '#374151', + particles: { + density: 8, + speed: 20 + }, + solid: { + borderRadius: 4 + } + }, + mention: { + color: '#1D4ED8', + backgroundColor: '#DBEAFE', + borderColor: '#BFDBFE', + borderWidth: 0, + borderRadius: 999, + paddingHorizontal: 6, + paddingVertical: 1, + fontFamily: '', + fontWeight: '500', + fontSize: 0, + pressedOpacity: 0.6 + }, + citation: { + color: '#2563EB', + fontSizeMultiplier: 0.7, + baselineOffsetPx: 0, + fontWeight: '', + underline: false, + backgroundColor: 'transparent', + paddingHorizontal: 0, + paddingVertical: 0, + borderColor: 'transparent', + borderWidth: 0, + borderRadius: 999 + } +}); +const refCache = new WeakMap(); +const structuralCache = []; +const LRU_MAX = 8; +const styleReferenceKeys = Object.keys(DEFAULT_NORMALIZED_STYLE); +export const normalizeMarkdownStyle = style => { + if (!style || Object.keys(style).length === 0) return DEFAULT_NORMALIZED_STYLE; + const refHit = refCache.get(style); + if (refHit) return refHit; + const structIdx = structuralCache.findIndex(e => isStyleEqual(e.style, style, styleReferenceKeys)); + if (structIdx !== -1) { + const entry = structuralCache.splice(structIdx, 1)[0]; + structuralCache.unshift(entry); + refCache.set(style, entry.result); + return entry.result; + } + const result = {}; + Object.keys(DEFAULT_NORMALIZED_STYLE).forEach(key => { + const userValue = style[key]; + result[key] = mergeSubStyle(DEFAULT_NORMALIZED_STYLE[key], userValue); + }); + if (style.taskList?.checkboxSize === undefined) { + const listSize = result.list.fontSize; + result.taskList.checkboxSize = Math.round(listSize * 0.9); + } + const finalResult = Object.freeze(result); + refCache.set(style, finalResult); + structuralCache.unshift({ + style, + result: finalResult + }); + if (structuralCache.length > LRU_MAX) structuralCache.pop(); + return finalResult; +}; +//# sourceMappingURL=normalizeMarkdownStyle.web.js.map \ No newline at end of file diff --git a/lib/module/normalizeMarkdownStyle.web.js.map b/lib/module/normalizeMarkdownStyle.web.js.map new file mode 100644 index 00000000..568c6899 --- /dev/null +++ b/lib/module/normalizeMarkdownStyle.web.js.map @@ -0,0 +1 @@ +{"version":3,"names":["isStyleEqual","mergeSubStyle","SYSTEM_FONT","MONOSPACE_FONT","defaultTextColor","defaultHeadingColor","baseHeader","fontFamily","fontWeight","marginTop","marginBottom","textAlign","DEFAULT_NORMALIZED_STYLE","Object","freeze","paragraph","fontSize","color","lineHeight","h1","h2","h3","h4","h5","h6","blockquote","borderColor","borderWidth","gapWidth","backgroundColor","list","bulletColor","bulletSize","markerMinWidth","markerColor","markerFontWeight","marginLeft","codeBlock","borderRadius","padding","link","underline","strong","undefined","em","fontStyle","strikethrough","code","image","height","inlineImage","size","thematicBreak","table","headerFontFamily","headerBackgroundColor","headerTextColor","rowEvenBackgroundColor","rowOddBackgroundColor","cellPaddingHorizontal","cellPaddingVertical","math","inlineMath","taskList","checkedColor","checkboxSize","checkboxBorderRadius","checkmarkColor","checkedTextColor","checkedStrikethrough","spoiler","particles","density","speed","solid","mention","paddingHorizontal","paddingVertical","pressedOpacity","citation","fontSizeMultiplier","baselineOffsetPx","refCache","WeakMap","structuralCache","LRU_MAX","styleReferenceKeys","keys","normalizeMarkdownStyle","style","length","refHit","get","structIdx","findIndex","e","entry","splice","unshift","set","result","forEach","key","userValue","listSize","Math","round","finalResult","pop"],"sourceRoot":"../../src","sources":["normalizeMarkdownStyle.web.ts"],"mappings":";;AAMA,SAASA,YAAY,EAAEC,aAAa,QAAQ,iBAAc;AAE1D,MAAMC,WAAW,GACf,8EAA8E;AAChF,MAAMC,cAAc,GAClB,kGAAkG;AAEpG,MAAMC,gBAAgB,GAAG,SAAS;AAClC,MAAMC,mBAAmB,GAAG,SAAS;AAErC,MAAMC,UAML,GAAG;EACFC,UAAU,EAAEL,WAAW;EACvBM,UAAU,EAAE,EAAE;EACdC,SAAS,EAAE,CAAC;EACZC,YAAY,EAAE,CAAC;EACfC,SAAS,EAAE;AACb,CAAC;AAED,MAAMC,wBAA+C,GAAGC,MAAM,CAACC,MAAM,CAAC;EACpEC,SAAS,EAAE;IACTC,QAAQ,EAAE,EAAE;IACZT,UAAU,EAAEL,WAAW;IACvBM,UAAU,EAAE,EAAE;IACdS,KAAK,EAAEb,gBAAgB;IACvBc,UAAU,EAAE,EAAE;IACdT,SAAS,EAAE,CAAC;IACZC,YAAY,EAAE,EAAE;IAChBC,SAAS,EAAE;EACb,CAAC;EACDQ,EAAE,EAAE;IACF,GAAGb,UAAU;IACbU,QAAQ,EAAE,EAAE;IACZC,KAAK,EAAEZ,mBAAmB;IAC1Ba,UAAU,EAAE;EACd,CAAC;EACDE,EAAE,EAAE;IACF,GAAGd,UAAU;IACbU,QAAQ,EAAE,EAAE;IACZC,KAAK,EAAEZ,mBAAmB;IAC1Ba,UAAU,EAAE;EACd,CAAC;EACDG,EAAE,EAAE;IACF,GAAGf,UAAU;IACbU,QAAQ,EAAE,EAAE;IACZC,KAAK,EAAEZ,mBAAmB;IAC1Ba,UAAU,EAAE;EACd,CAAC;EACDI,EAAE,EAAE;IACF,GAAGhB,UAAU;IACbU,QAAQ,EAAE,EAAE;IACZC,KAAK,EAAEZ,mBAAmB;IAC1Ba,UAAU,EAAE;EACd,CAAC;EACDK,EAAE,EAAE;IACF,GAAGjB,UAAU;IACbU,QAAQ,EAAE,EAAE;IACZC,KAAK,EAAE,SAAS;IAChBC,UAAU,EAAE;EACd,CAAC;EACDM,EAAE,EAAE;IACF,GAAGlB,UAAU;IACbU,QAAQ,EAAE,EAAE;IACZC,KAAK,EAAE,SAAS;IAChBC,UAAU,EAAE;EACd,CAAC;EACDO,UAAU,EAAE;IACVT,QAAQ,EAAE,EAAE;IACZT,UAAU,EAAEL,WAAW;IACvBM,UAAU,EAAE,EAAE;IACdS,KAAK,EAAE,SAAS;IAChBC,UAAU,EAAE,EAAE;IACdT,SAAS,EAAE,CAAC;IACZC,YAAY,EAAE,EAAE;IAChBgB,WAAW,EAAE,SAAS;IACtBC,WAAW,EAAE,CAAC;IACdC,QAAQ,EAAE,EAAE;IACZC,eAAe,EAAE;EACnB,CAAC;EACDC,IAAI,EAAE;IACJd,QAAQ,EAAE,EAAE;IACZT,UAAU,EAAEL,WAAW;IACvBM,UAAU,EAAE,EAAE;IACdS,KAAK,EAAEb,gBAAgB;IACvBc,UAAU,EAAE,EAAE;IACdT,SAAS,EAAE,CAAC;IACZC,YAAY,EAAE,EAAE;IAChBqB,WAAW,EAAE,SAAS;IACtBC,UAAU,EAAE,CAAC;IACbC,cAAc,EAAE,CAAC;IACjBC,WAAW,EAAE,SAAS;IACtBC,gBAAgB,EAAE,KAAK;IACvBP,QAAQ,EAAE,EAAE;IACZQ,UAAU,EAAE;EACd,CAAC;EACDC,SAAS,EAAE;IACTrB,QAAQ,EAAE,EAAE;IACZT,UAAU,EAAEJ,cAAc;IAC1BK,UAAU,EAAE,EAAE;IACdS,KAAK,EAAE,SAAS;IAChBC,UAAU,EAAE,EAAE;IACdT,SAAS,EAAE,CAAC;IACZC,YAAY,EAAE,EAAE;IAChBmB,eAAe,EAAE,SAAS;IAC1BH,WAAW,EAAE,SAAS;IACtBY,YAAY,EAAE,CAAC;IACfX,WAAW,EAAE,CAAC;IACdY,OAAO,EAAE;EACX,CAAC;EACDC,IAAI,EAAE;IAAEjC,UAAU,EAAE,EAAE;IAAEU,KAAK,EAAE,SAAS;IAAEwB,SAAS,EAAE;EAAK,CAAC;EAC3DC,MAAM,EAAE;IAAEnC,UAAU,EAAE,EAAE;IAAEC,UAAU,EAAE,MAAM;IAAES,KAAK,EAAE0B;EAAU,CAAC;EAChEC,EAAE,EAAE;IACFrC,UAAU,EAAE,EAAE;IACdsC,SAAS,EAAE,QAA6B;IACxC5B,KAAK,EAAE0B;EACT,CAAC;EACDG,aAAa,EAAE;IAAE7B,KAAK,EAAE;EAAU,CAAC;EACnCwB,SAAS,EAAE;IAAExB,KAAK,EAAEb;EAAiB,CAAC;EACtC2C,IAAI,EAAE;IACJxC,UAAU,EAAEJ,cAAc;IAC1Ba,QAAQ,EAAE,CAAC;IACXC,KAAK,EAAE,SAAS;IAChBY,eAAe,EAAE,SAAS;IAC1BH,WAAW,EAAE;EACf,CAAC;EACDsB,KAAK,EAAE;IAAEC,MAAM,EAAE,GAAG;IAAEX,YAAY,EAAE,CAAC;IAAE7B,SAAS,EAAE,CAAC;IAAEC,YAAY,EAAE;EAAG,CAAC;EACvEwC,WAAW,EAAE;IAAEC,IAAI,EAAE;EAAG,CAAC;EACzBC,aAAa,EAAE;IACbnC,KAAK,EAAE,SAAS;IAChBgC,MAAM,EAAE,CAAC;IACTxC,SAAS,EAAE,EAAE;IACbC,YAAY,EAAE;EAChB,CAAC;EACD2C,KAAK,EAAE;IACLrC,QAAQ,EAAE,EAAE;IACZT,UAAU,EAAEL,WAAW;IACvBM,UAAU,EAAE,EAAE;IACdS,KAAK,EAAEb,gBAAgB;IACvBK,SAAS,EAAE,CAAC;IACZC,YAAY,EAAE,EAAE;IAChBQ,UAAU,EAAE,EAAE;IACdoC,gBAAgB,EAAE,EAAE;IACpBC,qBAAqB,EAAE,SAAS;IAChCC,eAAe,EAAE,SAAS;IAC1BC,sBAAsB,EAAE,SAAS;IACjCC,qBAAqB,EAAE,SAAS;IAChChC,WAAW,EAAE,SAAS;IACtBC,WAAW,EAAE,CAAC;IACdW,YAAY,EAAE,CAAC;IACfqB,qBAAqB,EAAE,EAAE;IACzBC,mBAAmB,EAAE;EACvB,CAAC;EACDC,IAAI,EAAE;IACJ7C,QAAQ,EAAE,EAAE;IACZC,KAAK,EAAEb,gBAAgB;IACvByB,eAAe,EAAE,SAAS;IAC1BU,OAAO,EAAE,EAAE;IACX9B,SAAS,EAAE,CAAC;IACZC,YAAY,EAAE,EAAE;IAChBC,SAAS,EAAE;EACb,CAAC;EACDmD,UAAU,EAAE;IAAE7C,KAAK,EAAEb;EAAiB,CAAC;EACvC2D,QAAQ,EAAE;IACRC,YAAY,EAAE,SAAS;IACvBtC,WAAW,EAAE,SAAS;IACtBuC,YAAY,EAAE,EAAE;IAChBC,oBAAoB,EAAE,CAAC;IACvBC,cAAc,EAAE,SAAS;IACzBC,gBAAgB,EAAE,SAAS;IAC3BC,oBAAoB,EAAE;EACxB,CAAC;EACD;EACAC,OAAO,EAAE;IACPrD,KAAK,EAAE,SAAS;IAChBsD,SAAS,EAAE;MAAEC,OAAO,EAAE,CAAC;MAAEC,KAAK,EAAE;IAAG,CAAC;IACpCC,KAAK,EAAE;MAAEpC,YAAY,EAAE;IAAE;EAC3B,CAAC;EACDqC,OAAO,EAAE;IACP1D,KAAK,EAAE,SAAS;IAChBY,eAAe,EAAE,SAAS;IAC1BH,WAAW,EAAE,SAAS;IACtBC,WAAW,EAAE,CAAC;IACdW,YAAY,EAAE,GAAG;IACjBsC,iBAAiB,EAAE,CAAC;IACpBC,eAAe,EAAE,CAAC;IAClBtE,UAAU,EAAE,EAAE;IACdC,UAAU,EAAE,KAAK;IACjBQ,QAAQ,EAAE,CAAC;IACX8D,cAAc,EAAE;EAClB,CAAC;EACDC,QAAQ,EAAE;IACR9D,KAAK,EAAE,SAAS;IAChB+D,kBAAkB,EAAE,GAAG;IACvBC,gBAAgB,EAAE,CAAC;IACnBzE,UAAU,EAAE,EAAE;IACdiC,SAAS,EAAE,KAAK;IAChBZ,eAAe,EAAE,aAAa;IAC9B+C,iBAAiB,EAAE,CAAC;IACpBC,eAAe,EAAE,CAAC;IAClBnD,WAAW,EAAE,aAAa;IAC1BC,WAAW,EAAE,CAAC;IACdW,YAAY,EAAE;EAChB;AACF,CAAC,CAAC;AAEF,MAAM4C,QAAQ,GAAG,IAAIC,OAAO,CAAuC,CAAC;AACpE,MAAMC,eAGH,GAAG,EAAE;AACR,MAAMC,OAAO,GAAG,CAAC;AAEjB,MAAMC,kBAAkB,GAAGzE,MAAM,CAAC0E,IAAI,CAAC3E,wBAAwB,CAAC;AAEhE,OAAO,MAAM4E,sBAAsB,GACjCC,KAAoB,IACM;EAC1B,IAAI,CAACA,KAAK,IAAI5E,MAAM,CAAC0E,IAAI,CAACE,KAAK,CAAC,CAACC,MAAM,KAAK,CAAC,EAC3C,OAAO9E,wBAAwB;EAEjC,MAAM+E,MAAM,GAAGT,QAAQ,CAACU,GAAG,CAACH,KAAK,CAAC;EAClC,IAAIE,MAAM,EAAE,OAAOA,MAAM;EAEzB,MAAME,SAAS,GAAGT,eAAe,CAACU,SAAS,CAAEC,CAAC,IAC5C/F,YAAY,CAAC+F,CAAC,CAACN,KAAK,EAAEA,KAAK,EAAEH,kBAAkB,CACjD,CAAC;EACD,IAAIO,SAAS,KAAK,CAAC,CAAC,EAAE;IACpB,MAAMG,KAAK,GAAGZ,eAAe,CAACa,MAAM,CAACJ,SAAS,EAAE,CAAC,CAAC,CAAC,CAAC,CAAE;IACtDT,eAAe,CAACc,OAAO,CAACF,KAAK,CAAC;IAC9Bd,QAAQ,CAACiB,GAAG,CAACV,KAAK,EAAEO,KAAK,CAACI,MAAM,CAAC;IACjC,OAAOJ,KAAK,CAACI,MAAM;EACrB;EAEA,MAAMA,MAA+B,GAAG,CAAC,CAAC;EAExCvF,MAAM,CAAC0E,IAAI,CAAC3E,wBAAwB,CAAC,CACrCyF,OAAO,CAAEC,GAAG,IAAK;IACjB,MAAMC,SAAS,GAAGd,KAAK,CAACa,GAAG,CAEd;IACbF,MAAM,CAACE,GAAG,CAAC,GAAGrG,aAAa,CACzBW,wBAAwB,CAAC0F,GAAG,CAAC,EAC7BC,SACF,CAAC;EACH,CAAC,CAAC;EAEF,IAAId,KAAK,CAAC1B,QAAQ,EAAEE,YAAY,KAAKtB,SAAS,EAAE;IAC9C,MAAM6D,QAAQ,GAAIJ,MAAM,CAACtE,IAAI,CAA0Bd,QAAQ;IAC9DoF,MAAM,CAACrC,QAAQ,CAA8BE,YAAY,GAAGwC,IAAI,CAACC,KAAK,CACrEF,QAAQ,GAAG,GACb,CAAC;EACH;EAEA,MAAMG,WAAW,GAAG9F,MAAM,CAACC,MAAM,CAACsF,MAAM,CAAqC;EAC7ElB,QAAQ,CAACiB,GAAG,CAACV,KAAK,EAAEkB,WAAW,CAAC;EAChCvB,eAAe,CAACc,OAAO,CAAC;IAAET,KAAK;IAAEW,MAAM,EAAEO;EAAY,CAAC,CAAC;EACvD,IAAIvB,eAAe,CAACM,MAAM,GAAGL,OAAO,EAAED,eAAe,CAACwB,GAAG,CAAC,CAAC;EAE3D,OAAOD,WAAW;AACpB,CAAC","ignoreList":[]} diff --git a/lib/module/normalizeMarkdownTextInputStyle.js b/lib/module/normalizeMarkdownTextInputStyle.js new file mode 100644 index 00000000..0bafc38e --- /dev/null +++ b/lib/module/normalizeMarkdownTextInputStyle.js @@ -0,0 +1,53 @@ +"use strict"; + +import { processColor } from 'react-native'; +import { normalizeColor } from "./styleUtils.js"; +const DEFAULT_LINK_COLOR = '#2563EB'; +const DEFAULT_SPOILER_COLOR = '#374151'; +const DEFAULT_SPOILER_BG_COLOR = '#E5E7EB'; +const defaultInternal = Object.freeze({ + strong: { + color: undefined + }, + em: { + color: undefined + }, + link: { + color: processColor(DEFAULT_LINK_COLOR), + underline: true + }, + spoiler: { + color: processColor(DEFAULT_SPOILER_COLOR), + backgroundColor: processColor(DEFAULT_SPOILER_BG_COLOR) + } +}); +let cachedInput; +let cachedResult; +export const normalizeMarkdownTextInputStyle = style => { + if (!style || Object.keys(style).length === 0) { + return defaultInternal; + } + if (style === cachedInput && cachedResult) { + return cachedResult; + } + const result = { + strong: { + color: normalizeColor(style.strong?.color) + }, + em: { + color: normalizeColor(style.em?.color) + }, + link: { + color: normalizeColor(style.link?.color) ?? defaultInternal.link.color, + underline: style.link?.underline ?? defaultInternal.link.underline + }, + spoiler: { + color: normalizeColor(style.spoiler?.color) ?? defaultInternal.spoiler.color, + backgroundColor: normalizeColor(style.spoiler?.backgroundColor) ?? defaultInternal.spoiler.backgroundColor + } + }; + cachedInput = style; + cachedResult = result; + return result; +}; +//# sourceMappingURL=normalizeMarkdownTextInputStyle.js.map \ No newline at end of file diff --git a/lib/module/normalizeMarkdownTextInputStyle.js.map b/lib/module/normalizeMarkdownTextInputStyle.js.map new file mode 100644 index 00000000..b954f356 --- /dev/null +++ b/lib/module/normalizeMarkdownTextInputStyle.js.map @@ -0,0 +1 @@ +{"version":3,"names":["processColor","normalizeColor","DEFAULT_LINK_COLOR","DEFAULT_SPOILER_COLOR","DEFAULT_SPOILER_BG_COLOR","defaultInternal","Object","freeze","strong","color","undefined","em","link","underline","spoiler","backgroundColor","cachedInput","cachedResult","normalizeMarkdownTextInputStyle","style","keys","length","result"],"sourceRoot":"../../src","sources":["normalizeMarkdownTextInputStyle.ts"],"mappings":";;AAAA,SAASA,YAAY,QAAyB,cAAc;AAE5D,SAASC,cAAc,QAAQ,iBAAc;AAmB7C,MAAMC,kBAAkB,GAAG,SAAS;AACpC,MAAMC,qBAAqB,GAAG,SAAS;AACvC,MAAMC,wBAAwB,GAAG,SAAS;AAE1C,MAAMC,eAA+C,GAAGC,MAAM,CAACC,MAAM,CAAC;EACpEC,MAAM,EAAE;IACNC,KAAK,EAAEC;EACT,CAAC;EACDC,EAAE,EAAE;IACFF,KAAK,EAAEC;EACT,CAAC;EACDE,IAAI,EAAE;IACJH,KAAK,EAAET,YAAY,CAACE,kBAAkB,CAAE;IACxCW,SAAS,EAAE;EACb,CAAC;EACDC,OAAO,EAAE;IACPL,KAAK,EAAET,YAAY,CAACG,qBAAqB,CAAE;IAC3CY,eAAe,EAAEf,YAAY,CAACI,wBAAwB;EACxD;AACF,CAAC,CAAC;AAEF,IAAIY,WAA+C;AACnD,IAAIC,YAAwD;AAE5D,OAAO,MAAMC,+BAA+B,GAC1CC,KAA8B,IACK;EACnC,IAAI,CAACA,KAAK,IAAIb,MAAM,CAACc,IAAI,CAACD,KAAK,CAAC,CAACE,MAAM,KAAK,CAAC,EAAE;IAC7C,OAAOhB,eAAe;EACxB;EAEA,IAAIc,KAAK,KAAKH,WAAW,IAAIC,YAAY,EAAE;IACzC,OAAOA,YAAY;EACrB;EAEA,MAAMK,MAAsC,GAAG;IAC7Cd,MAAM,EAAE;MACNC,KAAK,EAAER,cAAc,CAACkB,KAAK,CAACX,MAAM,EAAEC,KAAK;IAC3C,CAAC;IACDE,EAAE,EAAE;MACFF,KAAK,EAAER,cAAc,CAACkB,KAAK,CAACR,EAAE,EAAEF,KAAK;IACvC,CAAC;IACDG,IAAI,EAAE;MACJH,KAAK,EAAER,cAAc,CAACkB,KAAK,CAACP,IAAI,EAAEH,KAAK,CAAC,IAAIJ,eAAe,CAACO,IAAI,CAACH,KAAK;MACtEI,SAAS,EAAEM,KAAK,CAACP,IAAI,EAAEC,SAAS,IAAIR,eAAe,CAACO,IAAI,CAACC;IAC3D,CAAC;IACDC,OAAO,EAAE;MACPL,KAAK,EACHR,cAAc,CAACkB,KAAK,CAACL,OAAO,EAAEL,KAAK,CAAC,IAAIJ,eAAe,CAACS,OAAO,CAACL,KAAK;MACvEM,eAAe,EACbd,cAAc,CAACkB,KAAK,CAACL,OAAO,EAAEC,eAAe,CAAC,IAC9CV,eAAe,CAACS,OAAO,CAACC;IAC5B;EACF,CAAC;EAEDC,WAAW,GAAGG,KAAK;EACnBF,YAAY,GAAGK,MAAM;EACrB,OAAOA,MAAM;AACf,CAAC","ignoreList":[]} diff --git a/lib/module/package.json b/lib/module/package.json new file mode 100644 index 00000000..089153bc --- /dev/null +++ b/lib/module/package.json @@ -0,0 +1 @@ +{"type":"module"} diff --git a/lib/module/plugin/withAndroidMath.js b/lib/module/plugin/withAndroidMath.js new file mode 100644 index 00000000..3fa84abc --- /dev/null +++ b/lib/module/plugin/withAndroidMath.js @@ -0,0 +1,23 @@ +"use strict"; + +import configPlugins from '@expo/config-plugins'; +const { + withGradleProperties +} = configPlugins; +export const withAndroidMath = (config, { + enableMath = true +}) => { + if (enableMath) { + return config; + } + return withGradleProperties(config, gradleConfig => { + gradleConfig.modResults = gradleConfig.modResults.filter(prop => prop.type !== 'property' || prop.key !== 'enrichedMarkdown.enableMath'); + gradleConfig.modResults.push({ + type: 'property', + key: 'enrichedMarkdown.enableMath', + value: 'false' + }); + return gradleConfig; + }); +}; +//# sourceMappingURL=withAndroidMath.js.map \ No newline at end of file diff --git a/lib/module/plugin/withAndroidMath.js.map b/lib/module/plugin/withAndroidMath.js.map new file mode 100644 index 00000000..9c68b60d --- /dev/null +++ b/lib/module/plugin/withAndroidMath.js.map @@ -0,0 +1 @@ +{"version":3,"names":["configPlugins","withGradleProperties","withAndroidMath","config","enableMath","gradleConfig","modResults","filter","prop","type","key","push","value"],"sourceRoot":"../../../src","sources":["plugin/withAndroidMath.ts"],"mappings":";;AAAA,OAAOA,aAAa,MAA6B,sBAAsB;AAEvE,MAAM;EAAEC;AAAqB,CAAC,GAAGD,aAAa;AAE9C,OAAO,MAAME,eAAuD,GAAGA,CACrEC,MAAM,EACN;EAAEC,UAAU,GAAG;AAAK,CAAC,KAClB;EACH,IAAIA,UAAU,EAAE;IACd,OAAOD,MAAM;EACf;EACA,OAAOF,oBAAoB,CAACE,MAAM,EAAGE,YAAY,IAAK;IACpDA,YAAY,CAACC,UAAU,GAAGD,YAAY,CAACC,UAAU,CAACC,MAAM,CACrDC,IAAI,IACHA,IAAI,CAACC,IAAI,KAAK,UAAU,IAAID,IAAI,CAACE,GAAG,KAAK,6BAC7C,CAAC;IAEDL,YAAY,CAACC,UAAU,CAACK,IAAI,CAAC;MAC3BF,IAAI,EAAE,UAAU;MAChBC,GAAG,EAAE,6BAA6B;MAClCE,KAAK,EAAE;IACT,CAAC,CAAC;IAEF,OAAOP,YAAY;EACrB,CAAC,CAAC;AACJ,CAAC","ignoreList":[]} diff --git a/lib/module/plugin/withIosMath.js b/lib/module/plugin/withIosMath.js new file mode 100644 index 00000000..9c1124d9 --- /dev/null +++ b/lib/module/plugin/withIosMath.js @@ -0,0 +1,26 @@ +"use strict"; + +import configPlugins from '@expo/config-plugins'; +import fs from 'fs'; +import path from 'path'; +const { + withDangerousMod +} = configPlugins; +const IOS_MATH_OPTION = "ENV['ENRICHED_MARKDOWN_ENABLE_MATH'] = '0'"; +export const withIosMath = (config, { + enableMath = true +}) => { + if (enableMath) { + return config; + } + return withDangerousMod(config, ['ios', async modConfig => { + const file = path.join(modConfig.modRequest.platformProjectRoot, 'Podfile'); + const contents = fs.readFileSync(file, 'utf8'); + const lines = contents.split('\n'); + const filteredLines = lines.filter(line => !line.includes('ENRICHED_MARKDOWN_ENABLE_MATH')); + filteredLines.unshift(IOS_MATH_OPTION); + fs.writeFileSync(file, filteredLines.join('\n')); + return modConfig; + }]); +}; +//# sourceMappingURL=withIosMath.js.map \ No newline at end of file diff --git a/lib/module/plugin/withIosMath.js.map b/lib/module/plugin/withIosMath.js.map new file mode 100644 index 00000000..3d7ce7c8 --- /dev/null +++ b/lib/module/plugin/withIosMath.js.map @@ -0,0 +1 @@ +{"version":3,"names":["configPlugins","fs","path","withDangerousMod","IOS_MATH_OPTION","withIosMath","config","enableMath","modConfig","file","join","modRequest","platformProjectRoot","contents","readFileSync","lines","split","filteredLines","filter","line","includes","unshift","writeFileSync"],"sourceRoot":"../../../src","sources":["plugin/withIosMath.ts"],"mappings":";;AAAA,OAAOA,aAAa,MAA6B,sBAAsB;AACvE,OAAOC,EAAE,MAAM,IAAI;AACnB,OAAOC,IAAI,MAAM,MAAM;AAEvB,MAAM;EAAEC;AAAiB,CAAC,GAAGH,aAAa;AAE1C,MAAMI,eAAe,GAAG,4CAA4C;AAEpE,OAAO,MAAMC,WAAmD,GAAGA,CACjEC,MAAM,EACN;EAAEC,UAAU,GAAG;AAAK,CAAC,KAClB;EACH,IAAIA,UAAU,EAAE;IACd,OAAOD,MAAM;EACf;EACA,OAAOH,gBAAgB,CAACG,MAAM,EAAE,CAC9B,KAAK,EACL,MAAOE,SAAS,IAAK;IACnB,MAAMC,IAAI,GAAGP,IAAI,CAACQ,IAAI,CACpBF,SAAS,CAACG,UAAU,CAACC,mBAAmB,EACxC,SACF,CAAC;IACD,MAAMC,QAAQ,GAAGZ,EAAE,CAACa,YAAY,CAACL,IAAI,EAAE,MAAM,CAAC;IAE9C,MAAMM,KAAK,GAAGF,QAAQ,CAACG,KAAK,CAAC,IAAI,CAAC;IAClC,MAAMC,aAAa,GAAGF,KAAK,CAACG,MAAM,CAC/BC,IAAI,IAAK,CAACA,IAAI,CAACC,QAAQ,CAAC,+BAA+B,CAC1D,CAAC;IAEDH,aAAa,CAACI,OAAO,CAACjB,eAAe,CAAC;IAEtCH,EAAE,CAACqB,aAAa,CAACb,IAAI,EAAEQ,aAAa,CAACP,IAAI,CAAC,IAAI,CAAC,CAAC;IAEhD,OAAOF,SAAS;EAClB,CAAC,CACF,CAAC;AACJ,CAAC","ignoreList":[]} diff --git a/lib/module/plugin/withReactNativeEnrichedMarkdown.js b/lib/module/plugin/withReactNativeEnrichedMarkdown.js new file mode 100644 index 00000000..8f56559e --- /dev/null +++ b/lib/module/plugin/withReactNativeEnrichedMarkdown.js @@ -0,0 +1,16 @@ +"use strict"; + +import { withIosMath } from "./withIosMath.js"; +import { withAndroidMath } from "./withAndroidMath.js"; +const withEnrichedMarkdown = (config, props) => { + const enableMath = props?.enableMath !== false; + config = withAndroidMath(config, { + enableMath + }); + config = withIosMath(config, { + enableMath + }); + return config; +}; +export default withEnrichedMarkdown; +//# sourceMappingURL=withReactNativeEnrichedMarkdown.js.map \ No newline at end of file diff --git a/lib/module/plugin/withReactNativeEnrichedMarkdown.js.map b/lib/module/plugin/withReactNativeEnrichedMarkdown.js.map new file mode 100644 index 00000000..da36fa62 --- /dev/null +++ b/lib/module/plugin/withReactNativeEnrichedMarkdown.js.map @@ -0,0 +1 @@ +{"version":3,"names":["withIosMath","withAndroidMath","withEnrichedMarkdown","config","props","enableMath"],"sourceRoot":"../../../src","sources":["plugin/withReactNativeEnrichedMarkdown.ts"],"mappings":";;AACA,SAASA,WAAW,QAAQ,kBAAe;AAC3C,SAASC,eAAe,QAAQ,sBAAmB;AAEnD,MAAMC,oBAAmE,GAAGA,CAC1EC,MAAM,EACNC,KAAK,KACF;EACH,MAAMC,UAAU,GAAGD,KAAK,EAAEC,UAAU,KAAK,KAAK;EAE9CF,MAAM,GAAGF,eAAe,CAACE,MAAM,EAAE;IAAEE;EAAW,CAAC,CAAC;EAChDF,MAAM,GAAGH,WAAW,CAACG,MAAM,EAAE;IAAEE;EAAW,CAAC,CAAC;EAE5C,OAAOF,MAAM;AACf,CAAC;AAED,eAAeD,oBAAoB","ignoreList":[]} diff --git a/lib/module/styleUtils.js b/lib/module/styleUtils.js new file mode 100644 index 00000000..818311d1 --- /dev/null +++ b/lib/module/styleUtils.js @@ -0,0 +1,64 @@ +"use strict"; + +import { Platform, processColor } from 'react-native'; +export const normalizeColor = color => { + if (!color) return undefined; + if (Platform.OS === 'web') return color; + return processColor(color) ?? undefined; +}; +export function mergeSubStyle(defaultStyle, userStyle) { + if (!userStyle) return defaultStyle; + const result = { + ...defaultStyle, + ...userStyle + }; + for (const key in result) { + const defaultValue = defaultStyle[key]; + const userValue = userStyle[key]; + if (typeof defaultValue === 'object' && defaultValue !== null && !Array.isArray(defaultValue) && typeof userValue === 'object' && userValue !== null && !Array.isArray(userValue)) { + result[key] = { + ...defaultValue, + ...userValue + }; + } + if (key.toLowerCase().includes('color') && typeof result[key] === 'string') { + result[key] = normalizeColor(result[key]); + } + } + return result; +} +function isSubStyleEqual(a, b) { + const keys = Object.keys(a); + if (keys.length !== Object.keys(b).length) return false; + for (const key of keys) { + const valueA = a[key]; + const valueB = b[key]; + if (valueA === valueB) continue; + if (typeof valueA === 'object' && valueA !== null && typeof valueB === 'object' && valueB !== null) { + const nestedKeysA = Object.keys(valueA); + const nestedKeysB = Object.keys(valueB); + if (nestedKeysA.length !== nestedKeysB.length) return false; + for (const nestedKey of nestedKeysA) { + if (valueA[nestedKey] !== valueB[nestedKey]) { + return false; + } + } + continue; + } + return false; + } + return true; +} +export function isStyleEqual(a, b, referenceKeys) { + for (const key of referenceKeys) { + const subA = a[key]; + const subB = b[key]; + if (subA === subB) continue; + if (!subA || !subB) return false; + if (!isSubStyleEqual(subA, subB)) { + return false; + } + } + return true; +} +//# sourceMappingURL=styleUtils.js.map \ No newline at end of file diff --git a/lib/module/styleUtils.js.map b/lib/module/styleUtils.js.map new file mode 100644 index 00000000..a88a2695 --- /dev/null +++ b/lib/module/styleUtils.js.map @@ -0,0 +1 @@ +{"version":3,"names":["Platform","processColor","normalizeColor","color","undefined","OS","mergeSubStyle","defaultStyle","userStyle","result","key","defaultValue","userValue","Array","isArray","toLowerCase","includes","isSubStyleEqual","a","b","keys","Object","length","valueA","valueB","nestedKeysA","nestedKeysB","nestedKey","isStyleEqual","referenceKeys","subA","subB"],"sourceRoot":"../../src","sources":["styleUtils.ts"],"mappings":";;AAAA,SAASA,QAAQ,EAAEC,YAAY,QAAyB,cAAc;AAGtE,OAAO,MAAMC,cAAc,GACzBC,KAAyB,IACE;EAC3B,IAAI,CAACA,KAAK,EAAE,OAAOC,SAAS;EAC5B,IAAIJ,QAAQ,CAACK,EAAE,KAAK,KAAK,EAAE,OAAOF,KAAK;EACvC,OAAOF,YAAY,CAACE,KAAK,CAAC,IAAIC,SAAS;AACzC,CAAC;AAED,OAAO,SAASE,aAAaA,CAC3BC,YAAe,EACfC,SAAsB,EACnB;EACH,IAAI,CAACA,SAAS,EAAE,OAAOD,YAAY;EACnC,MAAME,MAA+B,GAAG;IAAE,GAAGF,YAAY;IAAE,GAAGC;EAAU,CAAC;EACzE,KAAK,MAAME,GAAG,IAAID,MAAM,EAAE;IACxB,MAAME,YAAY,GAAGJ,YAAY,CAACG,GAAG,CAAC;IACtC,MAAME,SAAS,GAAGJ,SAAS,CAACE,GAAG,CAAC;IAChC,IACE,OAAOC,YAAY,KAAK,QAAQ,IAChCA,YAAY,KAAK,IAAI,IACrB,CAACE,KAAK,CAACC,OAAO,CAACH,YAAY,CAAC,IAC5B,OAAOC,SAAS,KAAK,QAAQ,IAC7BA,SAAS,KAAK,IAAI,IAClB,CAACC,KAAK,CAACC,OAAO,CAACF,SAAS,CAAC,EACzB;MACAH,MAAM,CAACC,GAAG,CAAC,GAAG;QACZ,GAAIC,YAAwC;QAC5C,GAAIC;MACN,CAAC;IACH;IACA,IACEF,GAAG,CAACK,WAAW,CAAC,CAAC,CAACC,QAAQ,CAAC,OAAO,CAAC,IACnC,OAAOP,MAAM,CAACC,GAAG,CAAC,KAAK,QAAQ,EAC/B;MACAD,MAAM,CAACC,GAAG,CAAC,GAAGR,cAAc,CAACO,MAAM,CAACC,GAAG,CAAW,CAAC;IACrD;EACF;EACA,OAAOD,MAAM;AACf;AAEA,SAASQ,eAAeA,CACtBC,CAA0B,EAC1BC,CAA0B,EACjB;EACT,MAAMC,IAAI,GAAGC,MAAM,CAACD,IAAI,CAACF,CAAC,CAAC;EAC3B,IAAIE,IAAI,CAACE,MAAM,KAAKD,MAAM,CAACD,IAAI,CAACD,CAAC,CAAC,CAACG,MAAM,EAAE,OAAO,KAAK;EACvD,KAAK,MAAMZ,GAAG,IAAIU,IAAI,EAAE;IACtB,MAAMG,MAAM,GAAGL,CAAC,CAACR,GAAG,CAAC;IACrB,MAAMc,MAAM,GAAGL,CAAC,CAACT,GAAG,CAAC;IACrB,IAAIa,MAAM,KAAKC,MAAM,EAAE;IACvB,IACE,OAAOD,MAAM,KAAK,QAAQ,IAC1BA,MAAM,KAAK,IAAI,IACf,OAAOC,MAAM,KAAK,QAAQ,IAC1BA,MAAM,KAAK,IAAI,EACf;MACA,MAAMC,WAAW,GAAGJ,MAAM,CAACD,IAAI,CAACG,MAAM,CAAC;MACvC,MAAMG,WAAW,GAAGL,MAAM,CAACD,IAAI,CAACI,MAAM,CAAC;MACvC,IAAIC,WAAW,CAACH,MAAM,KAAKI,WAAW,CAACJ,MAAM,EAAE,OAAO,KAAK;MAC3D,KAAK,MAAMK,SAAS,IAAIF,WAAW,EAAE;QACnC,IACGF,MAAM,CAA6BI,SAAS,CAAC,KAC7CH,MAAM,CAA6BG,SAAS,CAAC,EAC9C;UACA,OAAO,KAAK;QACd;MACF;MACA;IACF;IACA,OAAO,KAAK;EACd;EACA,OAAO,IAAI;AACb;AAEA,OAAO,SAASC,YAAYA,CAC1BV,CAAgB,EAChBC,CAAgB,EAChBU,aAAgC,EACvB;EACT,KAAK,MAAMnB,GAAG,IAAImB,aAAa,EAAE;IAC/B,MAAMC,IAAI,GAAGZ,CAAC,CAACR,GAAG,CAAwB;IAC1C,MAAMqB,IAAI,GAAGZ,CAAC,CAACT,GAAG,CAAwB;IAC1C,IAAIoB,IAAI,KAAKC,IAAI,EAAE;IACnB,IAAI,CAACD,IAAI,IAAI,CAACC,IAAI,EAAE,OAAO,KAAK;IAChC,IACE,CAACd,eAAe,CACda,IAAI,EACJC,IACF,CAAC,EACD;MACA,OAAO,KAAK;IACd;EACF;EACA,OAAO,IAAI;AACb","ignoreList":[]} diff --git a/lib/module/types/MarkdownStyle.js b/lib/module/types/MarkdownStyle.js new file mode 100644 index 00000000..57d8d522 --- /dev/null +++ b/lib/module/types/MarkdownStyle.js @@ -0,0 +1,2 @@ +"use strict"; +//# sourceMappingURL=MarkdownStyle.js.map \ No newline at end of file diff --git a/lib/module/types/MarkdownStyle.js.map b/lib/module/types/MarkdownStyle.js.map new file mode 100644 index 00000000..af7e2d76 --- /dev/null +++ b/lib/module/types/MarkdownStyle.js.map @@ -0,0 +1 @@ +{"version":3,"names":[],"sourceRoot":"../../../src","sources":["types/MarkdownStyle.ts"],"mappings":"","ignoreList":[]} diff --git a/lib/module/types/MarkdownStyleInternal.js b/lib/module/types/MarkdownStyleInternal.js new file mode 100644 index 00000000..bf53fb01 --- /dev/null +++ b/lib/module/types/MarkdownStyleInternal.js @@ -0,0 +1,2 @@ +"use strict"; +//# sourceMappingURL=MarkdownStyleInternal.js.map \ No newline at end of file diff --git a/lib/module/types/MarkdownStyleInternal.js.map b/lib/module/types/MarkdownStyleInternal.js.map new file mode 100644 index 00000000..c90a55f2 --- /dev/null +++ b/lib/module/types/MarkdownStyleInternal.js.map @@ -0,0 +1 @@ +{"version":3,"names":[],"sourceRoot":"../../../src","sources":["types/MarkdownStyleInternal.ts"],"mappings":"","ignoreList":[]} diff --git a/lib/module/types/MarkdownTextProps.js b/lib/module/types/MarkdownTextProps.js new file mode 100644 index 00000000..637d6585 --- /dev/null +++ b/lib/module/types/MarkdownTextProps.js @@ -0,0 +1,4 @@ +"use strict"; + +export {}; +//# sourceMappingURL=MarkdownTextProps.js.map \ No newline at end of file diff --git a/lib/module/types/MarkdownTextProps.js.map b/lib/module/types/MarkdownTextProps.js.map new file mode 100644 index 00000000..d01c66b2 --- /dev/null +++ b/lib/module/types/MarkdownTextProps.js.map @@ -0,0 +1 @@ +{"version":3,"names":[],"sourceRoot":"../../../src","sources":["types/MarkdownTextProps.ts"],"mappings":"","ignoreList":[]} diff --git a/lib/module/types/MarkdownTextProps.web.js b/lib/module/types/MarkdownTextProps.web.js new file mode 100644 index 00000000..a36933a4 --- /dev/null +++ b/lib/module/types/MarkdownTextProps.web.js @@ -0,0 +1,4 @@ +"use strict"; + +export {}; +//# sourceMappingURL=MarkdownTextProps.web.js.map \ No newline at end of file diff --git a/lib/module/types/MarkdownTextProps.web.js.map b/lib/module/types/MarkdownTextProps.web.js.map new file mode 100644 index 00000000..86759388 --- /dev/null +++ b/lib/module/types/MarkdownTextProps.web.js.map @@ -0,0 +1 @@ +{"version":3,"names":[],"sourceRoot":"../../../src","sources":["types/MarkdownTextProps.web.ts"],"mappings":"","ignoreList":[]} diff --git a/lib/module/types/events.js b/lib/module/types/events.js new file mode 100644 index 00000000..99f35993 --- /dev/null +++ b/lib/module/types/events.js @@ -0,0 +1,2 @@ +"use strict"; +//# sourceMappingURL=events.js.map \ No newline at end of file diff --git a/lib/module/types/events.js.map b/lib/module/types/events.js.map new file mode 100644 index 00000000..e2cbebbe --- /dev/null +++ b/lib/module/types/events.js.map @@ -0,0 +1 @@ +{"version":3,"names":[],"sourceRoot":"../../../src","sources":["types/events.ts"],"mappings":"","ignoreList":[]} diff --git a/lib/module/utils/regexParser.js b/lib/module/utils/regexParser.js new file mode 100644 index 00000000..6aa8f78d --- /dev/null +++ b/lib/module/utils/regexParser.js @@ -0,0 +1,43 @@ +"use strict"; + +const DISABLED_REGEX = { + pattern: '', + caseInsensitive: false, + dotAll: false, + isDisabled: true, + isDefault: false +}; +const DEFAULT_REGEX = { + pattern: '', + caseInsensitive: false, + dotAll: false, + isDisabled: false, + isDefault: true +}; +export const toNativeRegexConfig = regex => { + if (regex === null) { + return DISABLED_REGEX; + } + if (regex === undefined) { + return DEFAULT_REGEX; + } + const source = regex.source; + const hasLookbehind = source.includes('(?<=') || source.includes('(? { + const normalizedStyle = useMemo(() => normalizeMarkdownStyle(markdownStyle), [markdownStyle]); + const [ast, setAst] = useState(null); + const [katex, setKatex] = useState(null); + const [parseError, setParseError] = useState(false); + const { + underline = false, + latexMath = true + } = md4cFlags; + useEffect(() => { + let cancelled = false; + const katexPromise = latexMath ? loadKaTeX() : Promise.resolve(null); + Promise.all([parseMarkdown(markdown, { + underline, + latexMath + }), katexPromise]).then(([result, katexInstance]) => { + if (!cancelled) { + indexTaskItems(result); + markInlineImages(result); + setParseError(false); + setKatex(katexInstance); + setAst(result); + } + }).catch(error => { + if (!cancelled) { + if (__DEV__) { + console.error('[EnrichedMarkdownText] Parse failed:', error); + } + setParseError(true); + setAst(null); + setKatex(null); + } + }); + return () => { + cancelled = true; + }; + }, [markdown, underline, latexMath]); + const callbacks = useMemo(() => ({ + onLinkPress, + onLinkLongPress, + onTaskListItemPress, + onMentionPress, + onCitationPress + }), [onLinkPress, onLinkLongPress, onTaskListItemPress, onMentionPress, onCitationPress]); + const capabilities = useMemo(() => ({ + katex + }), [katex]); + const lastChildStyle = useMemo(() => allowTrailingMargin ? normalizedStyle : zeroTrailingMargins(normalizedStyle), [normalizedStyle, allowTrailingMargin]); + const styles = useMemo(() => buildStyles(normalizedStyle), [normalizedStyle]); + const lastChildStyles = useMemo(() => buildStyles(lastChildStyle), [lastChildStyle]); + const wrapperStyle = useMemo(() => { + const selectionColorCss = selectionColor ? normalizeColor(String(selectionColor)) : undefined; + return { + display: 'flex', + flexDirection: 'column', + ...containerStyle, + ...(selectable ? undefined : { + userSelect: 'none' + }), + ...(selectionColorCss != null ? { + ['--enrm-selection-bg']: selectionColorCss + } : null) + }; + }, [containerStyle, selectable, selectionColor]); + const selectionStyle = selectionColor ? /*#__PURE__*/_jsx("style", { + children: `[data-enriched-markdown-text] ::selection { + background-color: var(--enrm-selection-bg); + }` + }) : null; + + // The browser's default copy picks up the text content of the selected + // DOM, which would include citation markers. Citations are reference + // metadata, not prose, so we rewrite the plain-text flavor to elide them + // while keeping the HTML flavor intact for rich-text destinations. + // + // Mentions render a tiny sibling + ) : null; + + // The browser's default copy picks up the text content of the selected + // DOM, which would include citation markers. Citations are reference + // metadata, not prose, so we rewrite the plain-text flavor to elide them + // while keeping the HTML flavor intact for rich-text destinations. + // + // Mentions render a tiny sibling + + {displayText} + + + ); +} + +function CitationRenderer({ + url, + styles, + callbacks, + node, + renderChildren, +}: SchemeRendererProps) { + const targetUrl = url.slice(CITATION_SCHEME.length); + const displayText = extractNodeText(node); + + const handleClick = (event: MouseEvent) => { + event.preventDefault(); + callbacks.onCitationPress?.({ url: targetUrl, text: displayText }); + }; + + return ( + + {renderChildren(node)} + + ); +} + function LatexMathInlineRenderer({ node, styles, diff --git a/src/web/styles.ts b/src/web/styles.ts index 4d0ff8e0..dd333e2b 100644 --- a/src/web/styles.ts +++ b/src/web/styles.ts @@ -244,6 +244,57 @@ function linkStyle(style: MarkdownStyleInternal): CSSProperties { }; } +function mentionStyle(style: MarkdownStyleInternal): CSSProperties { + const mention = style.mention; + return { + display: 'inline-flex', + alignItems: 'center', + boxSizing: 'border-box', + color: mention.color, + backgroundColor: mention.backgroundColor, + borderColor: mention.borderColor, + borderStyle: mention.borderWidth > 0 ? 'solid' : undefined, + borderWidth: mention.borderWidth, + borderRadius: mention.borderRadius, + paddingInline: mention.paddingHorizontal, + paddingBlock: mention.paddingVertical, + fontFamily: normalizeFontFamily(mention.fontFamily), + fontWeight: normalizeFontWeight(mention.fontWeight), + fontSize: mention.fontSize || undefined, + cursor: 'pointer', + transition: 'opacity 0.12s ease-in-out', + lineHeight: 1, + }; +} + +function citationStyle(style: MarkdownStyleInternal): CSSProperties { + const citation = style.citation; + const hasBackground = + !!citation.backgroundColor && citation.backgroundColor !== 'transparent'; + const hasBorder = + !!citation.borderColor && + citation.borderColor !== 'transparent' && + citation.borderWidth > 0; + return { + color: citation.color, + fontSize: `calc(1em * ${citation.fontSizeMultiplier})`, + verticalAlign: 'baseline', + position: 'relative', + top: citation.baselineOffsetPx ? -citation.baselineOffsetPx : undefined, + fontWeight: normalizeFontWeight(citation.fontWeight), + backgroundColor: hasBackground ? citation.backgroundColor : undefined, + textDecoration: citation.underline ? 'underline' : undefined, + paddingInline: citation.paddingHorizontal || undefined, + paddingBlock: citation.paddingVertical || undefined, + borderStyle: hasBorder ? 'solid' : undefined, + borderColor: hasBorder ? citation.borderColor : undefined, + borderWidth: hasBorder ? citation.borderWidth : undefined, + borderRadius: + hasBackground || hasBorder ? citation.borderRadius : undefined, + cursor: 'pointer', + }; +} + function strikethroughStyle(style: MarkdownStyleInternal): CSSProperties { return { textDecorationLine: 'line-through', @@ -410,6 +461,9 @@ export interface Styles { tableHeaderCell: Record; tableCell: Record; taskCheckbox: CSSProperties; + mention: CSSProperties; + citation: CSSProperties; + mentionPressedOpacity: number; } type ColumnAlign = 'left' | 'center' | 'right' | 'default'; @@ -462,6 +516,9 @@ export function buildStyles(style: MarkdownStyleInternal): Styles { default: tableCellStyle(style, 'default'), }, taskCheckbox: taskCheckboxStyle(style), + mention: mentionStyle(style), + citation: citationStyle(style), + mentionPressedOpacity: style.mention.pressedOpacity, }; stylesStore.set(style, result); diff --git a/src/web/types.ts b/src/web/types.ts index 3a297c54..50d7469e 100644 --- a/src/web/types.ts +++ b/src/web/types.ts @@ -5,6 +5,8 @@ import type { LinkPressEvent, LinkLongPressEvent, TaskListItemPressEvent, + MentionPressEvent, + CitationPressEvent, } from '../types/events'; import type { KaTeXInstance } from './katex'; @@ -68,6 +70,8 @@ export interface RendererCallbacks { onLinkPress?: (event: LinkPressEvent) => void; onLinkLongPress?: (event: LinkLongPressEvent) => void; onTaskListItemPress?: (event: TaskListItemPressEvent) => void; + onMentionPress?: (event: MentionPressEvent) => void; + onCitationPress?: (event: CitationPressEvent) => void; } export interface RenderCapabilities {