react-native-enriched-markdown-scaffold 1.0.2-scaffold.2 → 1.0.2-scaffold.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (135) hide show
  1. package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownManagerDelegate.java +3 -0
  2. package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownManagerInterface.java +1 -0
  3. package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownTextManagerDelegate.java +3 -0
  4. package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownTextManagerInterface.java +1 -0
  5. package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/EventEmitters.cpp +72 -0
  6. package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/EventEmitters.h +50 -0
  7. package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/Props.cpp +10 -0
  8. package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/Props.h +134 -0
  9. package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdown.kt +62 -7
  10. package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownInternalText.kt +4 -0
  11. package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownManager.kt +13 -0
  12. package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownText.kt +42 -0
  13. package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownTextManager.kt +12 -0
  14. package/android/src/main/java/com/swmansion/enriched/markdown/events/CopyRequestEvent.kt +28 -0
  15. package/android/src/main/java/com/swmansion/enriched/markdown/events/LinkLayoutEvent.kt +36 -0
  16. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/LinkRenderer.kt +37 -7
  17. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/SpanStyleCache.kt +5 -1
  18. package/android/src/main/java/com/swmansion/enriched/markdown/spans/CodeBackgroundSpan.kt +13 -99
  19. package/android/src/main/java/com/swmansion/enriched/markdown/spans/InlineChipPainter.kt +140 -0
  20. package/android/src/main/java/com/swmansion/enriched/markdown/spans/LinkChipSpans.kt +177 -0
  21. package/android/src/main/java/com/swmansion/enriched/markdown/spans/LinkSpan.kt +1 -6
  22. package/android/src/main/java/com/swmansion/enriched/markdown/styles/LinkStyle.kt +36 -1
  23. package/android/src/main/java/com/swmansion/enriched/markdown/styles/LinkVariantEntry.kt +7 -3
  24. package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/MarkdownViewManagerUtils.kt +33 -0
  25. package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/conversion/HTMLGenerator.kt +2 -1
  26. package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/conversion/MarkdownExtractor.kt +6 -0
  27. package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/view/LinkLayoutCollector.kt +100 -0
  28. package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/view/SelectionActionMode.kt +24 -2
  29. package/android/src/main/java/com/swmansion/enriched/markdown/views/BlockMenuOptions.kt +27 -8
  30. package/android/src/main/java/com/swmansion/enriched/markdown/views/CodeBlockContainerView.kt +9 -1
  31. package/android/src/main/java/com/swmansion/enriched/markdown/views/TableContainerView.kt +18 -2
  32. package/android/src/math/java/com/swmansion/enriched/markdown/views/MathContainerView.kt +3 -1
  33. package/docs/API_REFERENCE.md +101 -0
  34. package/docs/COPY_OPTIONS.md +14 -0
  35. package/docs/MENTIONS.md +8 -1
  36. package/docs/STYLES.md +27 -0
  37. package/docs/TEXT.md +2 -0
  38. package/ios/EnrichedMarkdown.mm +91 -2
  39. package/ios/EnrichedMarkdownText.mm +64 -3
  40. package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/EventEmitters.cpp +72 -0
  41. package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/EventEmitters.h +50 -0
  42. package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/Props.cpp +10 -0
  43. package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/Props.h +134 -0
  44. package/ios/internals/MeasurementCache.h +5 -0
  45. package/ios/renderer/LinkRenderer.m +47 -15
  46. package/ios/styles/StyleConfig.h +16 -0
  47. package/ios/styles/StyleConfig.mm +60 -0
  48. package/ios/utils/CodeBackground.m +3 -65
  49. package/ios/utils/ENRMBlockMenu.h +12 -3
  50. package/ios/utils/ENRMChipDrawing.h +24 -0
  51. package/ios/utils/ENRMChipDrawing.m +83 -0
  52. package/ios/utils/ENRMLinkChip.h +70 -0
  53. package/ios/utils/ENRMLinkChip.m +194 -0
  54. package/ios/utils/ENRMLinkLayout.h +50 -0
  55. package/ios/utils/ENRMLinkLayout.m +45 -0
  56. package/ios/utils/EditMenuUtils+macOS.m +4 -1
  57. package/ios/utils/EditMenuUtils.h +10 -1
  58. package/ios/utils/EditMenuUtils.m +22 -5
  59. package/ios/utils/HTMLGenerator.m +2 -1
  60. package/ios/utils/MarkdownAccessibilityElementBuilder.m +4 -1
  61. package/ios/utils/MarkdownExtractor.m +2 -1
  62. package/ios/utils/RTFExportUtils.m +2 -0
  63. package/ios/utils/StylePropsUtils.h +37 -1
  64. package/ios/utils/TextViewLayoutManager.mm +3 -0
  65. package/ios/views/ENRMCodeBlockContainerView.h +4 -0
  66. package/ios/views/ENRMCodeBlockContainerView.m +8 -1
  67. package/ios/views/ENRMMathContainerView.h +4 -0
  68. package/ios/views/ENRMMathContainerView.m +8 -1
  69. package/ios/views/TableContainerView.h +7 -0
  70. package/ios/views/TableContainerView.m +30 -3
  71. package/lib/module/EnrichedMarkdownNativeComponent.ts +57 -0
  72. package/lib/module/EnrichedMarkdownTextNativeComponent.ts +57 -0
  73. package/lib/module/index.js.map +1 -1
  74. package/lib/module/native/EnrichedMarkdownText.js +119 -9
  75. package/lib/module/native/EnrichedMarkdownText.js.map +1 -1
  76. package/lib/module/normalizeMarkdownStyle.js +13 -2
  77. package/lib/module/normalizeMarkdownStyle.js.map +1 -1
  78. package/lib/module/normalizeMarkdownStyle.web.js +13 -2
  79. package/lib/module/normalizeMarkdownStyle.web.js.map +1 -1
  80. package/lib/module/web/EnrichedMarkdownText.js +6 -3
  81. package/lib/module/web/EnrichedMarkdownText.js.map +1 -1
  82. package/lib/module/web/renderers/InlineRenderers.js +96 -3
  83. package/lib/module/web/renderers/InlineRenderers.js.map +1 -1
  84. package/lib/module/web/styles.js +18 -0
  85. package/lib/module/web/styles.js.map +1 -1
  86. package/lib/module/web/utils.js +13 -0
  87. package/lib/module/web/utils.js.map +1 -1
  88. package/lib/typescript/src/EnrichedMarkdownNativeComponent.d.ts +53 -0
  89. package/lib/typescript/src/EnrichedMarkdownNativeComponent.d.ts.map +1 -1
  90. package/lib/typescript/src/EnrichedMarkdownTextNativeComponent.d.ts +53 -0
  91. package/lib/typescript/src/EnrichedMarkdownTextNativeComponent.d.ts.map +1 -1
  92. package/lib/typescript/src/index.d.ts +2 -2
  93. package/lib/typescript/src/index.d.ts.map +1 -1
  94. package/lib/typescript/src/index.web.d.ts +1 -1
  95. package/lib/typescript/src/index.web.d.ts.map +1 -1
  96. package/lib/typescript/src/native/EnrichedMarkdownText.d.ts +5 -5
  97. package/lib/typescript/src/native/EnrichedMarkdownText.d.ts.map +1 -1
  98. package/lib/typescript/src/normalizeMarkdownStyle.d.ts.map +1 -1
  99. package/lib/typescript/src/normalizeMarkdownStyle.web.d.ts.map +1 -1
  100. package/lib/typescript/src/types/MarkdownStyle.d.ts +28 -5
  101. package/lib/typescript/src/types/MarkdownStyle.d.ts.map +1 -1
  102. package/lib/typescript/src/types/MarkdownStyleInternal.d.ts +10 -0
  103. package/lib/typescript/src/types/MarkdownStyleInternal.d.ts.map +1 -1
  104. package/lib/typescript/src/types/MarkdownTextProps.d.ts +54 -1
  105. package/lib/typescript/src/types/MarkdownTextProps.d.ts.map +1 -1
  106. package/lib/typescript/src/types/MarkdownTextProps.web.d.ts +41 -1
  107. package/lib/typescript/src/types/MarkdownTextProps.web.d.ts.map +1 -1
  108. package/lib/typescript/src/types/events.d.ts +22 -0
  109. package/lib/typescript/src/types/events.d.ts.map +1 -1
  110. package/lib/typescript/src/web/EnrichedMarkdownText.d.ts +1 -1
  111. package/lib/typescript/src/web/EnrichedMarkdownText.d.ts.map +1 -1
  112. package/lib/typescript/src/web/renderers/InlineRenderers.d.ts.map +1 -1
  113. package/lib/typescript/src/web/styles.d.ts.map +1 -1
  114. package/lib/typescript/src/web/types.d.ts +4 -0
  115. package/lib/typescript/src/web/types.d.ts.map +1 -1
  116. package/lib/typescript/src/web/utils.d.ts +4 -0
  117. package/lib/typescript/src/web/utils.d.ts.map +1 -1
  118. package/package.json +1 -1
  119. package/src/EnrichedMarkdownNativeComponent.ts +57 -0
  120. package/src/EnrichedMarkdownTextNativeComponent.ts +57 -0
  121. package/src/index.tsx +3 -0
  122. package/src/index.web.tsx +5 -1
  123. package/src/native/EnrichedMarkdownText.tsx +127 -7
  124. package/src/normalizeMarkdownStyle.ts +13 -0
  125. package/src/normalizeMarkdownStyle.web.ts +11 -0
  126. package/src/types/MarkdownStyle.ts +29 -5
  127. package/src/types/MarkdownStyleInternal.ts +10 -0
  128. package/src/types/MarkdownTextProps.ts +56 -0
  129. package/src/types/MarkdownTextProps.web.ts +43 -1
  130. package/src/types/events.ts +23 -0
  131. package/src/web/EnrichedMarkdownText.tsx +10 -3
  132. package/src/web/renderers/InlineRenderers.tsx +111 -3
  133. package/src/web/styles.ts +25 -0
  134. package/src/web/types.ts +4 -0
  135. package/src/web/utils.ts +8 -0
@@ -6,6 +6,7 @@
6
6
  #import "ENRMAtomicSize.h"
7
7
  #import "ENRMContextMenuTextView+macOS.h"
8
8
  #import "ENRMImageAttachment.h"
9
+ #import "ENRMLinkLayout.h"
9
10
  #import "ENRMMarkdownParser.h"
10
11
  #import "ENRMSpoilerOverlayManager.h"
11
12
  #import "ENRMSpoilerTapUtils.h"
@@ -56,11 +57,13 @@ typedef NS_OPTIONS(NSUInteger, ENRMDirtyFlags) {
56
57
  - (void)setupLayoutManager;
57
58
  - (void)emitLinkPress:(NSString *)url;
58
59
  - (void)emitLinkLongPress:(NSString *)url;
60
+ - (void)emitLinkLayoutIfNeeded;
59
61
  - (void)emitTaskListItemPress:(NSInteger)index checked:(BOOL)checked text:(NSString *)text;
60
62
  - (void)emitContextMenuItemPress:(NSString *)itemText
61
63
  selectedText:(NSString *)selectedText
62
64
  selectionStart:(NSUInteger)selectionStart
63
65
  selectionEnd:(NSUInteger)selectionEnd;
66
+ - (void)emitCopyRequest:(NSString *)source markdown:(NSString *)markdown text:(NSString *)text whole:(BOOL)whole;
64
67
  @end
65
68
 
66
69
  @implementation EnrichedMarkdownText {
@@ -109,6 +112,9 @@ typedef NS_OPTIONS(NSUInteger, ENRMDirtyFlags) {
109
112
 
110
113
  ENRMSpoilerOverlayManager *_spoilerManager;
111
114
 
115
+ BOOL _emitLinkLayout;
116
+ NSArray<NSDictionary *> *_lastLinkLayout;
117
+
112
118
  NSLineBreakStrategy _lineBreakStrategy;
113
119
 
114
120
  ENRMWritingDirectionMode _writingDirectionMode;
@@ -182,6 +188,9 @@ typedef NS_OPTIONS(NSUInteger, ENRMDirtyFlags) {
182
188
  [super updateLayoutMetrics:layoutMetrics oldLayoutMetrics:oldLayoutMetrics];
183
189
 
184
190
  _lastCommittedSize.store(CGSizeMake(layoutMetrics.frame.size.width, layoutMetrics.frame.size.height));
191
+ #if TARGET_OS_OSX
192
+ [self emitLinkLayoutIfNeeded];
193
+ #endif
185
194
 
186
195
  NSWritingDirection resolved = _resolvedLayoutDirection;
187
196
  if (layoutMetrics.layoutDirection == LayoutDirection::RightToLeft) {
@@ -217,6 +226,7 @@ typedef NS_OPTIONS(NSUInteger, ENRMDirtyFlags) {
217
226
  if (needsHeightUpdate(measured, self.bounds)) {
218
227
  [self requestHeightUpdate];
219
228
  }
229
+ [self emitLinkLayoutIfNeeded];
220
230
  }
221
231
  }
222
232
 
@@ -301,8 +311,7 @@ typedef NS_OPTIONS(NSUInteger, ENRMDirtyFlags) {
301
311
  selectionEnd:selectionEnd];
302
312
  });
303
313
  return buildEditMenuForSelection(textView.textStorage, textView.selectedRange, strongSelf->_cachedMarkdown,
304
- strongSelf->_config, @[ baseMenu ], customItems,
305
- strongSelf -> _selectionMenuConfig);
314
+ strongSelf->_config, @[ baseMenu ], customItems, strongSelf->_selectionMenuConfig);
306
315
  };
307
316
  #endif
308
317
 
@@ -464,6 +473,8 @@ typedef NS_OPTIONS(NSUInteger, ENRMDirtyFlags) {
464
473
  if (forceHeightUpdate || needsHeightUpdate(measured, self.bounds)) {
465
474
  [self requestHeightUpdate];
466
475
  }
476
+
477
+ [self emitLinkLayoutIfNeeded];
467
478
  }
468
479
 
469
480
  if (_textView.hidden) {
@@ -484,6 +495,7 @@ typedef NS_OPTIONS(NSUInteger, ENRMDirtyFlags) {
484
495
  {
485
496
  [super layoutSubviews];
486
497
  [_spoilerManager updateIfNeeded];
498
+ [self emitLinkLayoutIfNeeded];
487
499
  }
488
500
  #endif
489
501
 
@@ -521,6 +533,12 @@ typedef NS_OPTIONS(NSUInteger, ENRMDirtyFlags) {
521
533
  }
522
534
  }
523
535
 
536
+ if (newViewProps.emitLinkLayout != _emitLinkLayout) {
537
+ _emitLinkLayout = newViewProps.emitLinkLayout;
538
+ _lastLinkLayout = nil;
539
+ [self emitLinkLayoutIfNeeded];
540
+ }
541
+
524
542
  if (_textView.selectable != newViewProps.selectable) {
525
543
  _textView.selectable = newViewProps.selectable;
526
544
  }
@@ -697,6 +715,8 @@ typedef NS_OPTIONS(NSUInteger, ENRMDirtyFlags) {
697
715
  _accessibilityNeedsRebuild = NO;
698
716
  [_spoilerManager removeAllOverlays];
699
717
  _spoilerManager = nil;
718
+ _emitLinkLayout = NO;
719
+ _lastLinkLayout = nil;
700
720
  if (_textView != nil) {
701
721
  ENRMSetAttributedText(_textView, [[NSAttributedString alloc] initWithString:@""]);
702
722
  _textView.hidden = YES;
@@ -742,6 +762,25 @@ Class<RCTComponentViewProtocol> EnrichedMarkdownTextCls(void)
742
762
  emitter->onLinkLongPress({.url = std::string(url.UTF8String)});
743
763
  }
744
764
 
765
+ /// Reports link rects to JS (for `renderLinkDecoration`). Called after every
766
+ /// render and layout change; deduplicated so an unchanged layout — the common
767
+ /// case during streaming — sends nothing.
768
+ - (void)emitLinkLayoutIfNeeded
769
+ {
770
+ if (!_emitLinkLayout || _renderedMarkdown == nil || self.bounds.size.width <= 0)
771
+ return;
772
+
773
+ auto emitter = std::static_pointer_cast<EnrichedMarkdownTextEventEmitter const>(_eventEmitter);
774
+ if (!emitter)
775
+ return;
776
+
777
+ NSArray<NSDictionary *> *fragments = ENRMCollectLinkLayoutFragments(_textView, CGPointZero, 0, NULL);
778
+ if (_lastLinkLayout != nil && [fragments isEqualToArray:_lastLinkLayout])
779
+ return;
780
+ _lastLinkLayout = fragments;
781
+ emitter->onLinkLayout(ENRMLinkLayoutEventFromFragments<EnrichedMarkdownTextEventEmitter::OnLinkLayout>(fragments));
782
+ }
783
+
745
784
  - (void)emitTaskListItemPress:(NSInteger)index checked:(BOOL)checked text:(NSString *)text
746
785
  {
747
786
  auto emitter = std::static_pointer_cast<EnrichedMarkdownTextEventEmitter const>(_eventEmitter);
@@ -749,6 +788,18 @@ Class<RCTComponentViewProtocol> EnrichedMarkdownTextCls(void)
749
788
  emitter->onTaskListItemPress({.index = (int)index, .checked = checked, .text = std::string(text.UTF8String ?: "")});
750
789
  }
751
790
 
791
+ - (void)emitCopyRequest:(NSString *)source markdown:(NSString *)markdown text:(NSString *)text whole:(BOOL)whole
792
+ {
793
+ auto emitter = std::static_pointer_cast<EnrichedMarkdownTextEventEmitter const>(_eventEmitter);
794
+ if (emitter)
795
+ emitter->onCopyRequest({
796
+ .source = std::string(source.UTF8String),
797
+ .markdown = std::string(markdown.UTF8String ?: ""),
798
+ .text = std::string(text.UTF8String ?: ""),
799
+ .whole = (bool)whole,
800
+ });
801
+ }
802
+
752
803
  - (void)emitContextMenuItemPress:(NSString *)itemText
753
804
  selectedText:(NSString *)selectedText
754
805
  selectionStart:(NSUInteger)selectionStart
@@ -831,8 +882,18 @@ Class<RCTComponentViewProtocol> EnrichedMarkdownTextCls(void)
831
882
  NSMutableArray<UIAction *> *customActions =
832
883
  ENRMBuildContextMenuActions(_contextMenuItemTexts, _contextMenuItemIcons, textView, range, handler);
833
884
 
885
+ // A full selection already carries the cached (original) markdown.
886
+ ENRMCopyRequestHandler onCopyRequest = ^(NSString *markdown, NSString *text, BOOL fullSelection) {
887
+ EnrichedMarkdownText *strongSelf = weakSelf;
888
+ if (strongSelf)
889
+ [strongSelf emitCopyRequest:@"selection"
890
+ markdown:markdown
891
+ text:text
892
+ whole:fullSelection && strongSelf->_cachedMarkdown.length > 0];
893
+ };
894
+
834
895
  return buildEditMenuForSelection(textView.attributedText, range, _cachedMarkdown, _config, suggestedActions,
835
- customActions, _selectionMenuConfig);
896
+ customActions, _selectionMenuConfig, onCopyRequest);
836
897
  }
837
898
  #endif
838
899
 
@@ -31,6 +31,30 @@ void EnrichedMarkdownEventEmitter::onLinkLongPress(OnLinkLongPress event) const
31
31
  }
32
32
 
33
33
 
34
+ void EnrichedMarkdownEventEmitter::onLinkLayout(OnLinkLayout event) const {
35
+ dispatchEvent("linkLayout", [event=std::move(event)](jsi::Runtime &runtime) {
36
+ auto payload = jsi::Object(runtime);
37
+
38
+ auto fragments = jsi::Array(runtime, event.fragments.size());
39
+ size_t fragmentsIndex = 0;
40
+ for (auto fragmentsValue : event.fragments) {
41
+ auto fragmentsObject = jsi::Object(runtime);
42
+ fragmentsObject.setProperty(runtime, "linkIndex", fragmentsValue.linkIndex);
43
+ fragmentsObject.setProperty(runtime, "url", fragmentsValue.url);
44
+ fragmentsObject.setProperty(runtime, "text", fragmentsValue.text);
45
+ fragmentsObject.setProperty(runtime, "x", fragmentsValue.x);
46
+ fragmentsObject.setProperty(runtime, "y", fragmentsValue.y);
47
+ fragmentsObject.setProperty(runtime, "width", fragmentsValue.width);
48
+ fragmentsObject.setProperty(runtime, "height", fragmentsValue.height);
49
+ fragments.setValueAtIndex(runtime, fragmentsIndex++, fragmentsObject);
50
+ }
51
+ payload.setProperty(runtime, "fragments", fragments);
52
+
53
+ return payload;
54
+ });
55
+ }
56
+
57
+
34
58
  void EnrichedMarkdownEventEmitter::onTaskListItemPress(OnTaskListItemPress event) const {
35
59
  dispatchEvent("taskListItemPress", [event=std::move(event)](jsi::Runtime &runtime) {
36
60
  auto payload = jsi::Object(runtime);
@@ -52,6 +76,18 @@ payload.setProperty(runtime, "language", event.language);
52
76
  }
53
77
 
54
78
 
79
+ void EnrichedMarkdownEventEmitter::onCopyRequest(OnCopyRequest event) const {
80
+ dispatchEvent("copyRequest", [event=std::move(event)](jsi::Runtime &runtime) {
81
+ auto payload = jsi::Object(runtime);
82
+ payload.setProperty(runtime, "source", event.source);
83
+ payload.setProperty(runtime, "markdown", event.markdown);
84
+ payload.setProperty(runtime, "text", event.text);
85
+ payload.setProperty(runtime, "whole", event.whole);
86
+ return payload;
87
+ });
88
+ }
89
+
90
+
55
91
  void EnrichedMarkdownEventEmitter::onContextMenuItemPress(OnContextMenuItemPress event) const {
56
92
  dispatchEvent("contextMenuItemPress", [event=std::move(event)](jsi::Runtime &runtime) {
57
93
  auto payload = jsi::Object(runtime);
@@ -358,6 +394,30 @@ void EnrichedMarkdownTextEventEmitter::onLinkLongPress(OnLinkLongPress event) co
358
394
  }
359
395
 
360
396
 
397
+ void EnrichedMarkdownTextEventEmitter::onLinkLayout(OnLinkLayout event) const {
398
+ dispatchEvent("linkLayout", [event=std::move(event)](jsi::Runtime &runtime) {
399
+ auto payload = jsi::Object(runtime);
400
+
401
+ auto fragments = jsi::Array(runtime, event.fragments.size());
402
+ size_t fragmentsIndex = 0;
403
+ for (auto fragmentsValue : event.fragments) {
404
+ auto fragmentsObject = jsi::Object(runtime);
405
+ fragmentsObject.setProperty(runtime, "linkIndex", fragmentsValue.linkIndex);
406
+ fragmentsObject.setProperty(runtime, "url", fragmentsValue.url);
407
+ fragmentsObject.setProperty(runtime, "text", fragmentsValue.text);
408
+ fragmentsObject.setProperty(runtime, "x", fragmentsValue.x);
409
+ fragmentsObject.setProperty(runtime, "y", fragmentsValue.y);
410
+ fragmentsObject.setProperty(runtime, "width", fragmentsValue.width);
411
+ fragmentsObject.setProperty(runtime, "height", fragmentsValue.height);
412
+ fragments.setValueAtIndex(runtime, fragmentsIndex++, fragmentsObject);
413
+ }
414
+ payload.setProperty(runtime, "fragments", fragments);
415
+
416
+ return payload;
417
+ });
418
+ }
419
+
420
+
361
421
  void EnrichedMarkdownTextEventEmitter::onTaskListItemPress(OnTaskListItemPress event) const {
362
422
  dispatchEvent("taskListItemPress", [event=std::move(event)](jsi::Runtime &runtime) {
363
423
  auto payload = jsi::Object(runtime);
@@ -379,6 +439,18 @@ payload.setProperty(runtime, "language", event.language);
379
439
  }
380
440
 
381
441
 
442
+ void EnrichedMarkdownTextEventEmitter::onCopyRequest(OnCopyRequest event) const {
443
+ dispatchEvent("copyRequest", [event=std::move(event)](jsi::Runtime &runtime) {
444
+ auto payload = jsi::Object(runtime);
445
+ payload.setProperty(runtime, "source", event.source);
446
+ payload.setProperty(runtime, "markdown", event.markdown);
447
+ payload.setProperty(runtime, "text", event.text);
448
+ payload.setProperty(runtime, "whole", event.whole);
449
+ return payload;
450
+ });
451
+ }
452
+
453
+
382
454
  void EnrichedMarkdownTextEventEmitter::onContextMenuItemPress(OnContextMenuItemPress event) const {
383
455
  dispatchEvent("contextMenuItemPress", [event=std::move(event)](jsi::Runtime &runtime) {
384
456
  auto payload = jsi::Object(runtime);
@@ -25,6 +25,20 @@ class EnrichedMarkdownEventEmitter : public ViewEventEmitter {
25
25
  std::string url;
26
26
  };
27
27
 
28
+ struct OnLinkLayoutFragments {
29
+ int linkIndex;
30
+ std::string url;
31
+ std::string text;
32
+ double x;
33
+ double y;
34
+ double width;
35
+ double height;
36
+ };
37
+
38
+ struct OnLinkLayout {
39
+ std::vector<OnLinkLayoutFragments> fragments;
40
+ };
41
+
28
42
  struct OnTaskListItemPress {
29
43
  int index;
30
44
  bool checked;
@@ -36,6 +50,13 @@ class EnrichedMarkdownEventEmitter : public ViewEventEmitter {
36
50
  std::string language;
37
51
  };
38
52
 
53
+ struct OnCopyRequest {
54
+ std::string source;
55
+ std::string markdown;
56
+ std::string text;
57
+ bool whole;
58
+ };
59
+
39
60
  struct OnContextMenuItemPress {
40
61
  std::string itemText;
41
62
  std::string selectedText;
@@ -46,10 +67,14 @@ class EnrichedMarkdownEventEmitter : public ViewEventEmitter {
46
67
 
47
68
  void onLinkLongPress(OnLinkLongPress value) const;
48
69
 
70
+ void onLinkLayout(OnLinkLayout value) const;
71
+
49
72
  void onTaskListItemPress(OnTaskListItemPress value) const;
50
73
 
51
74
  void onCopyPress(OnCopyPress value) const;
52
75
 
76
+ void onCopyRequest(OnCopyRequest value) const;
77
+
53
78
  void onContextMenuItemPress(OnContextMenuItemPress value) const;
54
79
  };
55
80
  class EnrichedMarkdownTextInputEventEmitter : public ViewEventEmitter {
@@ -292,6 +317,20 @@ class EnrichedMarkdownTextEventEmitter : public ViewEventEmitter {
292
317
  std::string url;
293
318
  };
294
319
 
320
+ struct OnLinkLayoutFragments {
321
+ int linkIndex;
322
+ std::string url;
323
+ std::string text;
324
+ double x;
325
+ double y;
326
+ double width;
327
+ double height;
328
+ };
329
+
330
+ struct OnLinkLayout {
331
+ std::vector<OnLinkLayoutFragments> fragments;
332
+ };
333
+
295
334
  struct OnTaskListItemPress {
296
335
  int index;
297
336
  bool checked;
@@ -303,6 +342,13 @@ class EnrichedMarkdownTextEventEmitter : public ViewEventEmitter {
303
342
  std::string language;
304
343
  };
305
344
 
345
+ struct OnCopyRequest {
346
+ std::string source;
347
+ std::string markdown;
348
+ std::string text;
349
+ bool whole;
350
+ };
351
+
306
352
  struct OnContextMenuItemPress {
307
353
  std::string itemText;
308
354
  std::string selectedText;
@@ -313,10 +359,14 @@ class EnrichedMarkdownTextEventEmitter : public ViewEventEmitter {
313
359
 
314
360
  void onLinkLongPress(OnLinkLongPress value) const;
315
361
 
362
+ void onLinkLayout(OnLinkLayout value) const;
363
+
316
364
  void onTaskListItemPress(OnTaskListItemPress value) const;
317
365
 
318
366
  void onCopyPress(OnCopyPress value) const;
319
367
 
368
+ void onCopyRequest(OnCopyRequest value) const;
369
+
320
370
  void onContextMenuItemPress(OnContextMenuItemPress value) const;
321
371
  };
322
372
  } // namespace facebook::react
@@ -21,6 +21,7 @@ EnrichedMarkdownProps::EnrichedMarkdownProps(
21
21
 
22
22
  markdown(convertRawProp(context, rawProps, "markdown", sourceProps.markdown, {})),
23
23
  markdownStyle(convertRawProp(context, rawProps, "markdownStyle", sourceProps.markdownStyle, {})),
24
+ emitLinkLayout(convertRawProp(context, rawProps, "emitLinkLayout", sourceProps.emitLinkLayout, {false})),
24
25
  enableTaskListItemToggle(convertRawProp(context, rawProps, "enableTaskListItemToggle", sourceProps.enableTaskListItemToggle, {true})),
25
26
  enableLinkPreview(convertRawProp(context, rawProps, "enableLinkPreview", sourceProps.enableLinkPreview, {true})),
26
27
  selectable(convertRawProp(context, rawProps, "selectable", sourceProps.selectable, {false})),
@@ -66,6 +67,10 @@ folly::dynamic EnrichedMarkdownProps::getDiffProps(
66
67
  result["markdownStyle"] = toDynamic(markdownStyle);
67
68
  }
68
69
 
70
+ if (emitLinkLayout != oldProps->emitLinkLayout) {
71
+ result["emitLinkLayout"] = emitLinkLayout;
72
+ }
73
+
69
74
  if (enableTaskListItemToggle != oldProps->enableTaskListItemToggle) {
70
75
  result["enableTaskListItemToggle"] = enableTaskListItemToggle;
71
76
  }
@@ -304,6 +309,7 @@ EnrichedMarkdownTextProps::EnrichedMarkdownTextProps(
304
309
 
305
310
  markdown(convertRawProp(context, rawProps, "markdown", sourceProps.markdown, {})),
306
311
  markdownStyle(convertRawProp(context, rawProps, "markdownStyle", sourceProps.markdownStyle, {})),
312
+ emitLinkLayout(convertRawProp(context, rawProps, "emitLinkLayout", sourceProps.emitLinkLayout, {false})),
307
313
  enableTaskListItemToggle(convertRawProp(context, rawProps, "enableTaskListItemToggle", sourceProps.enableTaskListItemToggle, {true})),
308
314
  enableLinkPreview(convertRawProp(context, rawProps, "enableLinkPreview", sourceProps.enableLinkPreview, {true})),
309
315
  selectable(convertRawProp(context, rawProps, "selectable", sourceProps.selectable, {false})),
@@ -349,6 +355,10 @@ folly::dynamic EnrichedMarkdownTextProps::getDiffProps(
349
355
  result["markdownStyle"] = toDynamic(markdownStyle);
350
356
  }
351
357
 
358
+ if (emitLinkLayout != oldProps->emitLinkLayout) {
359
+ result["emitLinkLayout"] = emitLinkLayout;
360
+ }
361
+
352
362
  if (enableTaskListItemToggle != oldProps->enableTaskListItemToggle) {
353
363
  result["enableTaskListItemToggle"] = enableTaskListItemToggle;
354
364
  }
@@ -997,6 +997,11 @@ struct EnrichedMarkdownMarkdownStyleLinkStruct {
997
997
  SharedColor color{};
998
998
  bool underline{false};
999
999
  SharedColor backgroundColor{};
1000
+ Float borderRadius{0.0};
1001
+ Float paddingHorizontal{0.0};
1002
+ Float paddingVertical{0.0};
1003
+ SharedColor borderColor{};
1004
+ Float borderWidth{0.0};
1000
1005
 
1001
1006
 
1002
1007
  #ifdef RN_SERIALIZABLE_STATE
@@ -1008,6 +1013,11 @@ struct EnrichedMarkdownMarkdownStyleLinkStruct {
1008
1013
  result["color"] = ::facebook::react::toDynamic(color);
1009
1014
  result["underline"] = underline;
1010
1015
  result["backgroundColor"] = ::facebook::react::toDynamic(backgroundColor);
1016
+ result["borderRadius"] = borderRadius;
1017
+ result["paddingHorizontal"] = paddingHorizontal;
1018
+ result["paddingVertical"] = paddingVertical;
1019
+ result["borderColor"] = ::facebook::react::toDynamic(borderColor);
1020
+ result["borderWidth"] = borderWidth;
1011
1021
  return result;
1012
1022
  }
1013
1023
  #endif
@@ -1032,6 +1042,26 @@ static inline void fromRawValue(const PropsParserContext& context, const RawValu
1032
1042
  if (tmp_backgroundColor != map.end()) {
1033
1043
  fromRawValue(context, tmp_backgroundColor->second, result.backgroundColor);
1034
1044
  }
1045
+ auto tmp_borderRadius = map.find("borderRadius");
1046
+ if (tmp_borderRadius != map.end()) {
1047
+ fromRawValue(context, tmp_borderRadius->second, result.borderRadius);
1048
+ }
1049
+ auto tmp_paddingHorizontal = map.find("paddingHorizontal");
1050
+ if (tmp_paddingHorizontal != map.end()) {
1051
+ fromRawValue(context, tmp_paddingHorizontal->second, result.paddingHorizontal);
1052
+ }
1053
+ auto tmp_paddingVertical = map.find("paddingVertical");
1054
+ if (tmp_paddingVertical != map.end()) {
1055
+ fromRawValue(context, tmp_paddingVertical->second, result.paddingVertical);
1056
+ }
1057
+ auto tmp_borderColor = map.find("borderColor");
1058
+ if (tmp_borderColor != map.end()) {
1059
+ fromRawValue(context, tmp_borderColor->second, result.borderColor);
1060
+ }
1061
+ auto tmp_borderWidth = map.find("borderWidth");
1062
+ if (tmp_borderWidth != map.end()) {
1063
+ fromRawValue(context, tmp_borderWidth->second, result.borderWidth);
1064
+ }
1035
1065
  }
1036
1066
 
1037
1067
  static inline std::string toString(const EnrichedMarkdownMarkdownStyleLinkStruct &value) {
@@ -1049,6 +1079,11 @@ struct EnrichedMarkdownMarkdownStyleLinkVariantsStruct {
1049
1079
  SharedColor color{};
1050
1080
  bool underline{false};
1051
1081
  SharedColor backgroundColor{};
1082
+ Float borderRadius{0.0};
1083
+ Float paddingHorizontal{0.0};
1084
+ Float paddingVertical{0.0};
1085
+ SharedColor borderColor{};
1086
+ Float borderWidth{0.0};
1052
1087
 
1053
1088
 
1054
1089
  #ifdef RN_SERIALIZABLE_STATE
@@ -1060,6 +1095,11 @@ struct EnrichedMarkdownMarkdownStyleLinkVariantsStruct {
1060
1095
  result["color"] = ::facebook::react::toDynamic(color);
1061
1096
  result["underline"] = underline;
1062
1097
  result["backgroundColor"] = ::facebook::react::toDynamic(backgroundColor);
1098
+ result["borderRadius"] = borderRadius;
1099
+ result["paddingHorizontal"] = paddingHorizontal;
1100
+ result["paddingVertical"] = paddingVertical;
1101
+ result["borderColor"] = ::facebook::react::toDynamic(borderColor);
1102
+ result["borderWidth"] = borderWidth;
1063
1103
  return result;
1064
1104
  }
1065
1105
  #endif
@@ -1084,6 +1124,26 @@ static inline void fromRawValue(const PropsParserContext& context, const RawValu
1084
1124
  if (tmp_backgroundColor != map.end()) {
1085
1125
  fromRawValue(context, tmp_backgroundColor->second, result.backgroundColor);
1086
1126
  }
1127
+ auto tmp_borderRadius = map.find("borderRadius");
1128
+ if (tmp_borderRadius != map.end()) {
1129
+ fromRawValue(context, tmp_borderRadius->second, result.borderRadius);
1130
+ }
1131
+ auto tmp_paddingHorizontal = map.find("paddingHorizontal");
1132
+ if (tmp_paddingHorizontal != map.end()) {
1133
+ fromRawValue(context, tmp_paddingHorizontal->second, result.paddingHorizontal);
1134
+ }
1135
+ auto tmp_paddingVertical = map.find("paddingVertical");
1136
+ if (tmp_paddingVertical != map.end()) {
1137
+ fromRawValue(context, tmp_paddingVertical->second, result.paddingVertical);
1138
+ }
1139
+ auto tmp_borderColor = map.find("borderColor");
1140
+ if (tmp_borderColor != map.end()) {
1141
+ fromRawValue(context, tmp_borderColor->second, result.borderColor);
1142
+ }
1143
+ auto tmp_borderWidth = map.find("borderWidth");
1144
+ if (tmp_borderWidth != map.end()) {
1145
+ fromRawValue(context, tmp_borderWidth->second, result.borderWidth);
1146
+ }
1087
1147
  }
1088
1148
 
1089
1149
  static inline std::string toString(const EnrichedMarkdownMarkdownStyleLinkVariantsStruct &value) {
@@ -2466,6 +2526,7 @@ struct EnrichedMarkdownSelectionMenuConfigStruct {
2466
2526
  bool copyFormatMarkdown{false};
2467
2527
  bool systemItemsNone{false};
2468
2528
  bool codeBlockCopyButton{false};
2529
+ bool interceptCopy{false};
2469
2530
 
2470
2531
 
2471
2532
  #ifdef RN_SERIALIZABLE_STATE
@@ -2484,6 +2545,7 @@ struct EnrichedMarkdownSelectionMenuConfigStruct {
2484
2545
  result["copyFormatMarkdown"] = copyFormatMarkdown;
2485
2546
  result["systemItemsNone"] = systemItemsNone;
2486
2547
  result["codeBlockCopyButton"] = codeBlockCopyButton;
2548
+ result["interceptCopy"] = interceptCopy;
2487
2549
  return result;
2488
2550
  }
2489
2551
  #endif
@@ -2536,6 +2598,10 @@ static inline void fromRawValue(const PropsParserContext& context, const RawValu
2536
2598
  if (tmp_codeBlockCopyButton != map.end()) {
2537
2599
  fromRawValue(context, tmp_codeBlockCopyButton->second, result.codeBlockCopyButton);
2538
2600
  }
2601
+ auto tmp_interceptCopy = map.find("interceptCopy");
2602
+ if (tmp_interceptCopy != map.end()) {
2603
+ fromRawValue(context, tmp_interceptCopy->second, result.interceptCopy);
2604
+ }
2539
2605
  }
2540
2606
 
2541
2607
  static inline std::string toString(const EnrichedMarkdownSelectionMenuConfigStruct &value) {
@@ -2820,6 +2886,7 @@ class EnrichedMarkdownProps final : public ViewProps {
2820
2886
 
2821
2887
  std::string markdown{};
2822
2888
  EnrichedMarkdownMarkdownStyleStruct markdownStyle{};
2889
+ bool emitLinkLayout{false};
2823
2890
  bool enableTaskListItemToggle{true};
2824
2891
  bool enableLinkPreview{true};
2825
2892
  bool selectable{false};
@@ -4974,6 +5041,11 @@ struct EnrichedMarkdownTextMarkdownStyleLinkStruct {
4974
5041
  SharedColor color{};
4975
5042
  bool underline{false};
4976
5043
  SharedColor backgroundColor{};
5044
+ Float borderRadius{0.0};
5045
+ Float paddingHorizontal{0.0};
5046
+ Float paddingVertical{0.0};
5047
+ SharedColor borderColor{};
5048
+ Float borderWidth{0.0};
4977
5049
 
4978
5050
 
4979
5051
  #ifdef RN_SERIALIZABLE_STATE
@@ -4985,6 +5057,11 @@ struct EnrichedMarkdownTextMarkdownStyleLinkStruct {
4985
5057
  result["color"] = ::facebook::react::toDynamic(color);
4986
5058
  result["underline"] = underline;
4987
5059
  result["backgroundColor"] = ::facebook::react::toDynamic(backgroundColor);
5060
+ result["borderRadius"] = borderRadius;
5061
+ result["paddingHorizontal"] = paddingHorizontal;
5062
+ result["paddingVertical"] = paddingVertical;
5063
+ result["borderColor"] = ::facebook::react::toDynamic(borderColor);
5064
+ result["borderWidth"] = borderWidth;
4988
5065
  return result;
4989
5066
  }
4990
5067
  #endif
@@ -5009,6 +5086,26 @@ static inline void fromRawValue(const PropsParserContext& context, const RawValu
5009
5086
  if (tmp_backgroundColor != map.end()) {
5010
5087
  fromRawValue(context, tmp_backgroundColor->second, result.backgroundColor);
5011
5088
  }
5089
+ auto tmp_borderRadius = map.find("borderRadius");
5090
+ if (tmp_borderRadius != map.end()) {
5091
+ fromRawValue(context, tmp_borderRadius->second, result.borderRadius);
5092
+ }
5093
+ auto tmp_paddingHorizontal = map.find("paddingHorizontal");
5094
+ if (tmp_paddingHorizontal != map.end()) {
5095
+ fromRawValue(context, tmp_paddingHorizontal->second, result.paddingHorizontal);
5096
+ }
5097
+ auto tmp_paddingVertical = map.find("paddingVertical");
5098
+ if (tmp_paddingVertical != map.end()) {
5099
+ fromRawValue(context, tmp_paddingVertical->second, result.paddingVertical);
5100
+ }
5101
+ auto tmp_borderColor = map.find("borderColor");
5102
+ if (tmp_borderColor != map.end()) {
5103
+ fromRawValue(context, tmp_borderColor->second, result.borderColor);
5104
+ }
5105
+ auto tmp_borderWidth = map.find("borderWidth");
5106
+ if (tmp_borderWidth != map.end()) {
5107
+ fromRawValue(context, tmp_borderWidth->second, result.borderWidth);
5108
+ }
5012
5109
  }
5013
5110
 
5014
5111
  static inline std::string toString(const EnrichedMarkdownTextMarkdownStyleLinkStruct &value) {
@@ -5026,6 +5123,11 @@ struct EnrichedMarkdownTextMarkdownStyleLinkVariantsStruct {
5026
5123
  SharedColor color{};
5027
5124
  bool underline{false};
5028
5125
  SharedColor backgroundColor{};
5126
+ Float borderRadius{0.0};
5127
+ Float paddingHorizontal{0.0};
5128
+ Float paddingVertical{0.0};
5129
+ SharedColor borderColor{};
5130
+ Float borderWidth{0.0};
5029
5131
 
5030
5132
 
5031
5133
  #ifdef RN_SERIALIZABLE_STATE
@@ -5037,6 +5139,11 @@ struct EnrichedMarkdownTextMarkdownStyleLinkVariantsStruct {
5037
5139
  result["color"] = ::facebook::react::toDynamic(color);
5038
5140
  result["underline"] = underline;
5039
5141
  result["backgroundColor"] = ::facebook::react::toDynamic(backgroundColor);
5142
+ result["borderRadius"] = borderRadius;
5143
+ result["paddingHorizontal"] = paddingHorizontal;
5144
+ result["paddingVertical"] = paddingVertical;
5145
+ result["borderColor"] = ::facebook::react::toDynamic(borderColor);
5146
+ result["borderWidth"] = borderWidth;
5040
5147
  return result;
5041
5148
  }
5042
5149
  #endif
@@ -5061,6 +5168,26 @@ static inline void fromRawValue(const PropsParserContext& context, const RawValu
5061
5168
  if (tmp_backgroundColor != map.end()) {
5062
5169
  fromRawValue(context, tmp_backgroundColor->second, result.backgroundColor);
5063
5170
  }
5171
+ auto tmp_borderRadius = map.find("borderRadius");
5172
+ if (tmp_borderRadius != map.end()) {
5173
+ fromRawValue(context, tmp_borderRadius->second, result.borderRadius);
5174
+ }
5175
+ auto tmp_paddingHorizontal = map.find("paddingHorizontal");
5176
+ if (tmp_paddingHorizontal != map.end()) {
5177
+ fromRawValue(context, tmp_paddingHorizontal->second, result.paddingHorizontal);
5178
+ }
5179
+ auto tmp_paddingVertical = map.find("paddingVertical");
5180
+ if (tmp_paddingVertical != map.end()) {
5181
+ fromRawValue(context, tmp_paddingVertical->second, result.paddingVertical);
5182
+ }
5183
+ auto tmp_borderColor = map.find("borderColor");
5184
+ if (tmp_borderColor != map.end()) {
5185
+ fromRawValue(context, tmp_borderColor->second, result.borderColor);
5186
+ }
5187
+ auto tmp_borderWidth = map.find("borderWidth");
5188
+ if (tmp_borderWidth != map.end()) {
5189
+ fromRawValue(context, tmp_borderWidth->second, result.borderWidth);
5190
+ }
5064
5191
  }
5065
5192
 
5066
5193
  static inline std::string toString(const EnrichedMarkdownTextMarkdownStyleLinkVariantsStruct &value) {
@@ -6443,6 +6570,7 @@ struct EnrichedMarkdownTextSelectionMenuConfigStruct {
6443
6570
  bool copyFormatMarkdown{false};
6444
6571
  bool systemItemsNone{false};
6445
6572
  bool codeBlockCopyButton{false};
6573
+ bool interceptCopy{false};
6446
6574
 
6447
6575
 
6448
6576
  #ifdef RN_SERIALIZABLE_STATE
@@ -6461,6 +6589,7 @@ struct EnrichedMarkdownTextSelectionMenuConfigStruct {
6461
6589
  result["copyFormatMarkdown"] = copyFormatMarkdown;
6462
6590
  result["systemItemsNone"] = systemItemsNone;
6463
6591
  result["codeBlockCopyButton"] = codeBlockCopyButton;
6592
+ result["interceptCopy"] = interceptCopy;
6464
6593
  return result;
6465
6594
  }
6466
6595
  #endif
@@ -6513,6 +6642,10 @@ static inline void fromRawValue(const PropsParserContext& context, const RawValu
6513
6642
  if (tmp_codeBlockCopyButton != map.end()) {
6514
6643
  fromRawValue(context, tmp_codeBlockCopyButton->second, result.codeBlockCopyButton);
6515
6644
  }
6645
+ auto tmp_interceptCopy = map.find("interceptCopy");
6646
+ if (tmp_interceptCopy != map.end()) {
6647
+ fromRawValue(context, tmp_interceptCopy->second, result.interceptCopy);
6648
+ }
6516
6649
  }
6517
6650
 
6518
6651
  static inline std::string toString(const EnrichedMarkdownTextSelectionMenuConfigStruct &value) {
@@ -6797,6 +6930,7 @@ class EnrichedMarkdownTextProps final : public ViewProps {
6797
6930
 
6798
6931
  std::string markdown{};
6799
6932
  EnrichedMarkdownTextMarkdownStyleStruct markdownStyle{};
6933
+ bool emitLinkLayout{false};
6800
6934
  bool enableTaskListItemToggle{true};
6801
6935
  bool enableLinkPreview{true};
6802
6936
  bool selectable{false};
@@ -128,6 +128,11 @@ template <typename StyleStruct> inline size_t computeStyleFingerprint(const Styl
128
128
  s.codeBlock.borderWidth);
129
129
  hashFields(s.code.fontFamily, s.code.fontSize);
130
130
  hashFields(s.link.fontFamily, s.strong.fontFamily, s.strong.fontWeight, s.em.fontFamily, s.em.fontStyle);
131
+ // Link chip horizontal padding reserves space in the line; variants can set their own.
132
+ hashFields(s.link.paddingHorizontal);
133
+ for (const auto &variant : s.linkVariants) {
134
+ hashFields(variant.pattern, variant.paddingHorizontal);
135
+ }
131
136
  hashFields(s.highlight.backgroundColor, s.highlight.color);
132
137
 
133
138
  // Visual/Spacing Elements