@tinglinzh/react-native-markdownview 0.1.0
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.
- package/Package.swift +33 -0
- package/ios/RNMarkdownView.swift +261 -0
- package/ios/RNMarkdownViewComponentView.h +16 -0
- package/ios/RNMarkdownViewComponentView.mm +128 -0
- package/ios/RNMarkdownViewManager.m +34 -0
- package/ios/RNMarkdownViewManager.swift +16 -0
- package/ios/react-native-markdownview-Bridging-Header.h +12 -0
- package/lib/commonjs/MarkdownView.js +139 -0
- package/lib/commonjs/MarkdownView.js.map +1 -0
- package/lib/commonjs/NativeMarkdownView.js +22 -0
- package/lib/commonjs/NativeMarkdownView.js.map +1 -0
- package/lib/commonjs/index.js +13 -0
- package/lib/commonjs/index.js.map +1 -0
- package/lib/commonjs/package.json +1 -0
- package/lib/commonjs/types.js +6 -0
- package/lib/commonjs/types.js.map +1 -0
- package/lib/module/MarkdownView.js +134 -0
- package/lib/module/MarkdownView.js.map +1 -0
- package/lib/module/NativeMarkdownView.js +21 -0
- package/lib/module/NativeMarkdownView.js.map +1 -0
- package/lib/module/index.js +13 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/types.js +4 -0
- package/lib/module/types.js.map +1 -0
- package/lib/typescript/src/MarkdownView.d.ts +25 -0
- package/lib/typescript/src/MarkdownView.d.ts.map +1 -0
- package/lib/typescript/src/NativeMarkdownView.d.ts +53 -0
- package/lib/typescript/src/NativeMarkdownView.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +12 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/lib/typescript/src/types.d.ts +126 -0
- package/lib/typescript/src/types.d.ts.map +1 -0
- package/package.json +67 -0
- package/react-native-markdownview.podspec +38 -0
- package/src/MarkdownView.tsx +164 -0
- package/src/NativeMarkdownView.ts +69 -0
- package/src/index.tsx +25 -0
- package/src/types.ts +143 -0
package/Package.swift
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// swift-tools-version: 5.9
|
|
2
|
+
// When consumed via Swift Package Manager, MarkdownView is fetched automatically.
|
|
3
|
+
// When consumed via CocoaPods, add MarkdownView to your Xcode project manually via
|
|
4
|
+
// File → Add Package Dependencies → https://github.com/HumanInterfaceDesign/MarkdownView
|
|
5
|
+
|
|
6
|
+
import PackageDescription
|
|
7
|
+
|
|
8
|
+
let package = Package(
|
|
9
|
+
name: "ReactNativeMarkdownView",
|
|
10
|
+
platforms: [.iOS(.v16)],
|
|
11
|
+
products: [
|
|
12
|
+
.library(
|
|
13
|
+
name: "ReactNativeMarkdownView",
|
|
14
|
+
targets: ["ReactNativeMarkdownView"]
|
|
15
|
+
)
|
|
16
|
+
],
|
|
17
|
+
dependencies: [
|
|
18
|
+
.package(
|
|
19
|
+
url: "https://github.com/HumanInterfaceDesign/MarkdownView",
|
|
20
|
+
branch: "main"
|
|
21
|
+
)
|
|
22
|
+
],
|
|
23
|
+
targets: [
|
|
24
|
+
.target(
|
|
25
|
+
name: "ReactNativeMarkdownView",
|
|
26
|
+
dependencies: [
|
|
27
|
+
.product(name: "MarkdownView", package: "MarkdownView")
|
|
28
|
+
],
|
|
29
|
+
path: "ios",
|
|
30
|
+
sources: ["RNMarkdownView.swift", "RNMarkdownViewManager.swift"]
|
|
31
|
+
)
|
|
32
|
+
]
|
|
33
|
+
)
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
import UIKit
|
|
2
|
+
import MarkdownView
|
|
3
|
+
|
|
4
|
+
/// UIView wrapper around MarkdownTextView for use in React Native.
|
|
5
|
+
/// Handles prop → native API mapping and event forwarding for both
|
|
6
|
+
/// the Old Architecture (via RNMarkdownViewManager) and the New
|
|
7
|
+
/// Architecture (Fabric, via RNMarkdownViewComponentView).
|
|
8
|
+
@objc public final class RNMarkdownView: UIView {
|
|
9
|
+
|
|
10
|
+
// MARK: - Internal view
|
|
11
|
+
|
|
12
|
+
private let markdownTextView = MarkdownTextView()
|
|
13
|
+
private var lastContentSize: CGSize = .zero
|
|
14
|
+
|
|
15
|
+
// MARK: - React props (Old Architecture uses KVC to set these)
|
|
16
|
+
|
|
17
|
+
/// The raw markdown string to render.
|
|
18
|
+
@objc public var markdown: String = "" {
|
|
19
|
+
didSet {
|
|
20
|
+
guard markdown != oldValue else { return }
|
|
21
|
+
markdownTextView.setMarkdown(string: markdown)
|
|
22
|
+
scheduleContentSizeNotification()
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/// JSON-encoded MarkdownTheme overrides. See ThemeOptions in types.ts for the shape.
|
|
27
|
+
@objc public var themeJSON: String? {
|
|
28
|
+
didSet {
|
|
29
|
+
guard themeJSON != oldValue else { return }
|
|
30
|
+
applyThemeJSON(themeJSON)
|
|
31
|
+
if !markdown.isEmpty {
|
|
32
|
+
markdownTextView.setMarkdown(string: markdown)
|
|
33
|
+
scheduleContentSizeNotification()
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// MARK: - Old Architecture event blocks
|
|
39
|
+
|
|
40
|
+
@objc public var onLinkPress: (([AnyHashable: Any]?) -> Void)?
|
|
41
|
+
@objc public var onImagePress: (([AnyHashable: Any]?) -> Void)?
|
|
42
|
+
@objc public var onLineSelection: (([AnyHashable: Any]?) -> Void)?
|
|
43
|
+
/// Fires when the natural content height changes. Payload: { contentSize: { width, height } }
|
|
44
|
+
@objc public var onContentSizeChange: (([AnyHashable: Any]?) -> Void)?
|
|
45
|
+
|
|
46
|
+
// MARK: - New Architecture (Fabric) callbacks – set by RNMarkdownViewComponentView.mm
|
|
47
|
+
|
|
48
|
+
var onLinkPressFabric: ((_ url: String, _ isURL: Bool) -> Void)?
|
|
49
|
+
var onImagePressFabric: ((_ source: String) -> Void)?
|
|
50
|
+
var onLineSelectionFabric: ((_ start: Int, _ end: Int, _ contents: [String], _ language: String?) -> Void)?
|
|
51
|
+
var onContentSizeChangeFabric: ((_ width: Double, _ height: Double) -> Void)?
|
|
52
|
+
|
|
53
|
+
// MARK: - Initializers
|
|
54
|
+
|
|
55
|
+
public override init(frame: CGRect) {
|
|
56
|
+
super.init(frame: frame)
|
|
57
|
+
setupView()
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
@available(*, unavailable)
|
|
61
|
+
required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }
|
|
62
|
+
|
|
63
|
+
// MARK: - Setup
|
|
64
|
+
|
|
65
|
+
private func setupView() {
|
|
66
|
+
addSubview(markdownTextView)
|
|
67
|
+
markdownTextView.translatesAutoresizingMaskIntoConstraints = false
|
|
68
|
+
NSLayoutConstraint.activate([
|
|
69
|
+
markdownTextView.topAnchor.constraint(equalTo: topAnchor),
|
|
70
|
+
markdownTextView.leadingAnchor.constraint(equalTo: leadingAnchor),
|
|
71
|
+
markdownTextView.trailingAnchor.constraint(equalTo: trailingAnchor),
|
|
72
|
+
markdownTextView.bottomAnchor.constraint(equalTo: bottomAnchor),
|
|
73
|
+
])
|
|
74
|
+
setupHandlers()
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
private func setupHandlers() {
|
|
78
|
+
markdownTextView.linkHandler = { [weak self] payload, _, _ in
|
|
79
|
+
guard let self else { return }
|
|
80
|
+
let (url, isURL): (String, Bool) = {
|
|
81
|
+
switch payload {
|
|
82
|
+
case .url(let u): return (u.absoluteString, true)
|
|
83
|
+
case .string(let s): return (s, false)
|
|
84
|
+
}
|
|
85
|
+
}()
|
|
86
|
+
self.onLinkPress?(["url": url, "isURL": isURL])
|
|
87
|
+
self.onLinkPressFabric?(url, isURL)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
markdownTextView.imageTapHandler = { [weak self] source, _ in
|
|
91
|
+
guard let self else { return }
|
|
92
|
+
self.onImagePress?(["source": source])
|
|
93
|
+
self.onImagePressFabric?(source)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
markdownTextView.lineSelectionHandler = { [weak self] info in
|
|
97
|
+
guard let self else { return }
|
|
98
|
+
guard let info else { return }
|
|
99
|
+
let body: [AnyHashable: Any] = [
|
|
100
|
+
"startLine": info.lineRange.lowerBound,
|
|
101
|
+
"endLine": info.lineRange.upperBound,
|
|
102
|
+
"contents": info.contents,
|
|
103
|
+
"language": info.language as Any,
|
|
104
|
+
]
|
|
105
|
+
self.onLineSelection?(body)
|
|
106
|
+
self.onLineSelectionFabric?(
|
|
107
|
+
info.lineRange.lowerBound,
|
|
108
|
+
info.lineRange.upperBound,
|
|
109
|
+
info.contents,
|
|
110
|
+
info.language
|
|
111
|
+
)
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// MARK: - Layout
|
|
116
|
+
|
|
117
|
+
public override func layoutSubviews() {
|
|
118
|
+
super.layoutSubviews()
|
|
119
|
+
scheduleContentSizeNotification()
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
private func scheduleContentSizeNotification() {
|
|
123
|
+
DispatchQueue.main.async { [weak self] in
|
|
124
|
+
self?.emitContentSizeIfChanged()
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
private func emitContentSizeIfChanged() {
|
|
129
|
+
let size = markdownTextView.intrinsicContentSize
|
|
130
|
+
guard size.height > 0, size != lastContentSize else { return }
|
|
131
|
+
lastContentSize = size
|
|
132
|
+
let body: [AnyHashable: Any] = [
|
|
133
|
+
"contentSize": ["width": Double(size.width), "height": Double(size.height)]
|
|
134
|
+
]
|
|
135
|
+
onContentSizeChange?(body)
|
|
136
|
+
onContentSizeChangeFabric?(Double(size.width), Double(size.height))
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// MARK: - Fabric entry-points (called from RNMarkdownViewComponentView.mm)
|
|
140
|
+
|
|
141
|
+
@objc public func applyMarkdownString(_ value: String) {
|
|
142
|
+
self.markdown = value
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
@objc public func applyThemeJSONString(_ value: String?) {
|
|
146
|
+
self.themeJSON = value
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// MARK: - Theme
|
|
150
|
+
|
|
151
|
+
private func applyThemeJSON(_ json: String?) {
|
|
152
|
+
guard
|
|
153
|
+
let json,
|
|
154
|
+
let data = json.data(using: .utf8),
|
|
155
|
+
let dict = try? JSONSerialization.jsonObject(with: data) as? [String: Any]
|
|
156
|
+
else { return }
|
|
157
|
+
|
|
158
|
+
var theme = MarkdownTheme()
|
|
159
|
+
|
|
160
|
+
applyColors(from: dict["colors"] as? [String: String], to: &theme)
|
|
161
|
+
applyFonts(from: dict["fonts"] as? [String: Any], to: &theme)
|
|
162
|
+
applySpacings(from: dict["spacings"] as? [String: CGFloat], to: &theme)
|
|
163
|
+
applyTable(from: dict["table"] as? [String: Any], to: &theme)
|
|
164
|
+
|
|
165
|
+
if let raw = dict["fontScale"] as? String,
|
|
166
|
+
let scale = MarkdownTheme.FontScale(rawValue: raw) {
|
|
167
|
+
theme.scaleFont(by: scale)
|
|
168
|
+
}
|
|
169
|
+
if let shows = dict["showsBlockHeaders"] as? Bool {
|
|
170
|
+
theme.showsBlockHeaders = shows
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
markdownTextView.theme = theme
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
private func applyColors(from dict: [String: String]?, to theme: inout MarkdownTheme) {
|
|
177
|
+
guard let dict else { return }
|
|
178
|
+
func set(_ key: String, _ apply: (UIColor) -> Void) {
|
|
179
|
+
if let hex = dict[key], let color = UIColor(hexString: hex) { apply(color) }
|
|
180
|
+
}
|
|
181
|
+
set("body") { theme.colors.body = $0 }
|
|
182
|
+
set("code") { theme.colors.code = $0 }
|
|
183
|
+
set("codeBackground") { theme.colors.codeBackground = $0 }
|
|
184
|
+
set("highlight") { theme.colors.highlight = $0 }
|
|
185
|
+
set("emphasis") { theme.colors.emphasis = $0 }
|
|
186
|
+
set("selectionTint") { theme.colors.selectionTint = $0 }
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
private func applyFonts(from dict: [String: Any]?, to theme: inout MarkdownTheme) {
|
|
190
|
+
guard let dict else { return }
|
|
191
|
+
let bodySize = dict["bodySize"] as? CGFloat ?? theme.fonts.body.pointSize
|
|
192
|
+
let codeSize = dict["codeSize"] as? CGFloat ?? theme.fonts.code.pointSize
|
|
193
|
+
|
|
194
|
+
let bodyFont: UIFont
|
|
195
|
+
if let name = dict["bodyName"] as? String, !name.isEmpty,
|
|
196
|
+
let f = UIFont(name: name, size: bodySize) {
|
|
197
|
+
bodyFont = f
|
|
198
|
+
} else {
|
|
199
|
+
bodyFont = .systemFont(ofSize: bodySize)
|
|
200
|
+
}
|
|
201
|
+
theme.fonts.body = bodyFont
|
|
202
|
+
theme.fonts.bold = UIFont(descriptor: bodyFont.fontDescriptor.withSymbolicTraits(.traitBold) ?? bodyFont.fontDescriptor, size: bodySize)
|
|
203
|
+
theme.fonts.italic = UIFont(descriptor: bodyFont.fontDescriptor.withSymbolicTraits(.traitItalic) ?? bodyFont.fontDescriptor, size: bodySize)
|
|
204
|
+
|
|
205
|
+
let codeFont: UIFont
|
|
206
|
+
if let name = dict["codeName"] as? String, !name.isEmpty,
|
|
207
|
+
let f = UIFont(name: name, size: codeSize) {
|
|
208
|
+
codeFont = f
|
|
209
|
+
} else {
|
|
210
|
+
codeFont = .monospacedSystemFont(ofSize: codeSize, weight: .regular)
|
|
211
|
+
}
|
|
212
|
+
theme.fonts.code = codeFont
|
|
213
|
+
theme.fonts.codeInline = codeFont
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
private func applySpacings(from dict: [String: CGFloat]?, to theme: inout MarkdownTheme) {
|
|
217
|
+
guard let dict else { return }
|
|
218
|
+
if let v = dict["general"] { theme.spacings.general = v }
|
|
219
|
+
if let v = dict["list"] { theme.spacings.list = v }
|
|
220
|
+
if let v = dict["final"] { theme.spacings.final = v }
|
|
221
|
+
if let v = dict["cell"] { theme.spacings.cell = v }
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
private func applyTable(from dict: [String: Any]?, to theme: inout MarkdownTheme) {
|
|
225
|
+
guard let dict else { return }
|
|
226
|
+
if let r = dict["cornerRadius"] as? CGFloat { theme.table.cornerRadius = r }
|
|
227
|
+
if let w = dict["borderWidth"] as? CGFloat { theme.table.borderWidth = w }
|
|
228
|
+
if let hex = dict["borderColor"] as? String,
|
|
229
|
+
let c = UIColor(hexString: hex) { theme.table.borderColor = c }
|
|
230
|
+
if let hex = dict["headerBackgroundColor"] as? String,
|
|
231
|
+
let c = UIColor(hexString: hex) { theme.table.headerBackgroundColor = c }
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// MARK: - UIColor hex initializer
|
|
236
|
+
|
|
237
|
+
private extension UIColor {
|
|
238
|
+
/// Accepts "#RRGGBB", "#RRGGBBAA", "RRGGBB", "RRGGBBAA".
|
|
239
|
+
convenience init?(hexString: String) {
|
|
240
|
+
var hex = hexString.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
241
|
+
if hex.hasPrefix("#") { hex = String(hex.dropFirst()) }
|
|
242
|
+
guard hex.count == 6 || hex.count == 8 else { return nil }
|
|
243
|
+
var value: UInt64 = 0
|
|
244
|
+
guard Scanner(string: hex).scanHexInt64(&value) else { return nil }
|
|
245
|
+
if hex.count == 6 {
|
|
246
|
+
self.init(
|
|
247
|
+
red: CGFloat((value & 0xFF0000) >> 16) / 255,
|
|
248
|
+
green: CGFloat((value & 0x00FF00) >> 8) / 255,
|
|
249
|
+
blue: CGFloat( value & 0x0000FF) / 255,
|
|
250
|
+
alpha: 1
|
|
251
|
+
)
|
|
252
|
+
} else {
|
|
253
|
+
self.init(
|
|
254
|
+
red: CGFloat((value & 0xFF000000) >> 24) / 255,
|
|
255
|
+
green: CGFloat((value & 0x00FF0000) >> 16) / 255,
|
|
256
|
+
blue: CGFloat((value & 0x0000FF00) >> 8) / 255,
|
|
257
|
+
alpha: CGFloat( value & 0x000000FF) / 255
|
|
258
|
+
)
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#ifdef RCT_NEW_ARCH_ENABLED
|
|
4
|
+
#import <React/RCTViewComponentView.h>
|
|
5
|
+
#import <UIKit/UIKit.h>
|
|
6
|
+
|
|
7
|
+
NS_ASSUME_NONNULL_BEGIN
|
|
8
|
+
|
|
9
|
+
/// Fabric component view for the New Architecture.
|
|
10
|
+
/// Wraps RNMarkdownView and bridges Fabric props/events.
|
|
11
|
+
@interface RNMarkdownViewComponentView : RCTViewComponentView
|
|
12
|
+
@end
|
|
13
|
+
|
|
14
|
+
NS_ASSUME_NONNULL_END
|
|
15
|
+
|
|
16
|
+
#endif // RCT_NEW_ARCH_ENABLED
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* New Architecture (Fabric) component view for RNMarkdownView.
|
|
3
|
+
*
|
|
4
|
+
* Codegen generates C++ headers from the NativeMarkdownView.ts spec.
|
|
5
|
+
* This file bridges those generated types to the Swift RNMarkdownView class.
|
|
6
|
+
*/
|
|
7
|
+
#ifdef RCT_NEW_ARCH_ENABLED
|
|
8
|
+
|
|
9
|
+
#import "RNMarkdownViewComponentView.h"
|
|
10
|
+
|
|
11
|
+
// Generated by codegen from NativeMarkdownView.ts
|
|
12
|
+
#import <react/renderer/components/RNMarkdownViewSpec/ComponentDescriptors.h>
|
|
13
|
+
#import <react/renderer/components/RNMarkdownViewSpec/EventEmitters.h>
|
|
14
|
+
#import <react/renderer/components/RNMarkdownViewSpec/Props.h>
|
|
15
|
+
#import <react/renderer/components/RNMarkdownViewSpec/RCTComponentViewHelpers.h>
|
|
16
|
+
|
|
17
|
+
#import "RCTFabricComponentsPlugins.h"
|
|
18
|
+
|
|
19
|
+
// Swift-generated header (module name derived from pod name with hyphens → underscores)
|
|
20
|
+
#import "react_native_markdownview-Swift.h"
|
|
21
|
+
|
|
22
|
+
using namespace facebook::react;
|
|
23
|
+
|
|
24
|
+
@interface RNMarkdownViewComponentView () <RCTRNMarkdownViewViewProtocol>
|
|
25
|
+
@end
|
|
26
|
+
|
|
27
|
+
@implementation RNMarkdownViewComponentView {
|
|
28
|
+
RNMarkdownView *_markdownView;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// ─── Lifecycle ───────────────────────────────────────────────────────────────
|
|
32
|
+
|
|
33
|
+
- (instancetype)initWithFrame:(CGRect)frame
|
|
34
|
+
{
|
|
35
|
+
if (self = [super initWithFrame:frame]) {
|
|
36
|
+
static const auto defaultProps = std::make_shared<const RNMarkdownViewProps>();
|
|
37
|
+
_props = defaultProps;
|
|
38
|
+
|
|
39
|
+
_markdownView = [[RNMarkdownView alloc] initWithFrame:frame];
|
|
40
|
+
self.contentView = _markdownView;
|
|
41
|
+
}
|
|
42
|
+
return self;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// ─── Fabric boilerplate ──────────────────────────────────────────────────────
|
|
46
|
+
|
|
47
|
+
+ (ComponentDescriptorProvider)componentDescriptorProvider
|
|
48
|
+
{
|
|
49
|
+
return concreteComponentDescriptorProvider<RNMarkdownViewComponentDescriptor>();
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// ─── Props ───────────────────────────────────────────────────────────────────
|
|
53
|
+
|
|
54
|
+
- (void)updateProps:(Props::Shared const &)props
|
|
55
|
+
oldProps:(Props::Shared const &)oldProps
|
|
56
|
+
{
|
|
57
|
+
const auto &newTyped = *std::static_pointer_cast<RNMarkdownViewProps const>(props);
|
|
58
|
+
const auto &oldTyped = *std::static_pointer_cast<RNMarkdownViewProps const>(oldProps);
|
|
59
|
+
|
|
60
|
+
if (newTyped.markdown != oldTyped.markdown) {
|
|
61
|
+
[_markdownView applyMarkdownString:@(newTyped.markdown.c_str())];
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (newTyped.themeJSON != oldTyped.themeJSON) {
|
|
65
|
+
NSString *json = newTyped.themeJSON.empty() ? nil : @(newTyped.themeJSON.c_str());
|
|
66
|
+
[_markdownView applyThemeJSONString:json];
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
[super updateProps:props oldProps:oldProps];
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// ─── Events ──────────────────────────────────────────────────────────────────
|
|
73
|
+
|
|
74
|
+
- (void)updateEventEmitter:(EventEmitter::Shared const &)eventEmitter
|
|
75
|
+
{
|
|
76
|
+
[super updateEventEmitter:eventEmitter];
|
|
77
|
+
auto emitter = std::static_pointer_cast<RNMarkdownViewEventEmitter const>(eventEmitter);
|
|
78
|
+
|
|
79
|
+
__weak typeof(self) weakSelf = self;
|
|
80
|
+
|
|
81
|
+
_markdownView.onLinkPressFabric = ^(NSString *url, BOOL isURL) {
|
|
82
|
+
if (!emitter) return;
|
|
83
|
+
RNMarkdownViewEventEmitter::OnLinkPress event;
|
|
84
|
+
event.url = std::string(url.UTF8String ?: "");
|
|
85
|
+
event.isURL = isURL;
|
|
86
|
+
emitter->onLinkPress(event);
|
|
87
|
+
(void)weakSelf;
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
_markdownView.onImagePressFabric = ^(NSString *source) {
|
|
91
|
+
if (!emitter) return;
|
|
92
|
+
RNMarkdownViewEventEmitter::OnImagePress event;
|
|
93
|
+
event.source = std::string(source.UTF8String ?: "");
|
|
94
|
+
emitter->onImagePress(event);
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
_markdownView.onLineSelectionFabric = ^(NSInteger start, NSInteger end, NSArray<NSString *> *contents, NSString * _Nullable language) {
|
|
98
|
+
if (!emitter) return;
|
|
99
|
+
RNMarkdownViewEventEmitter::OnLineSelection event;
|
|
100
|
+
event.startLine = static_cast<int>(start);
|
|
101
|
+
event.endLine = static_cast<int>(end);
|
|
102
|
+
for (NSString *line in contents) {
|
|
103
|
+
event.contents.push_back(std::string(line.UTF8String ?: ""));
|
|
104
|
+
}
|
|
105
|
+
event.language = language ? std::string(language.UTF8String) : "";
|
|
106
|
+
emitter->onLineSelection(event);
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
_markdownView.onContentSizeChangeFabric = ^(double width, double height) {
|
|
110
|
+
if (!emitter) return;
|
|
111
|
+
RNMarkdownViewEventEmitter::OnContentSizeChange event;
|
|
112
|
+
RNMarkdownViewEventEmitter::OnContentSizeChangeContentSize size;
|
|
113
|
+
size.width = width;
|
|
114
|
+
size.height = height;
|
|
115
|
+
event.contentSize = size;
|
|
116
|
+
emitter->onContentSizeChange(event);
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
@end
|
|
121
|
+
|
|
122
|
+
// Required by Fabric's component registry
|
|
123
|
+
Class<RCTComponentViewProtocol> RNMarkdownViewCls(void)
|
|
124
|
+
{
|
|
125
|
+
return RNMarkdownViewComponentView.class;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
#endif // RCT_NEW_ARCH_ENABLED
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Old Architecture bridge.
|
|
3
|
+
*
|
|
4
|
+
* React Native uses KVC to set these properties on the UIView returned by
|
|
5
|
+
* RNMarkdownViewManager.view(). The property names must match exactly what
|
|
6
|
+
* RNMarkdownView exposes via @objc.
|
|
7
|
+
*/
|
|
8
|
+
#import <React/RCTViewManager.h>
|
|
9
|
+
|
|
10
|
+
@interface RCT_EXTERN_MODULE(RNMarkdownViewManager, RCTViewManager)
|
|
11
|
+
|
|
12
|
+
// ─── Content ────────────────────────────────────────────────────────────────
|
|
13
|
+
/// Raw markdown string.
|
|
14
|
+
RCT_EXPORT_VIEW_PROPERTY(markdown, NSString)
|
|
15
|
+
|
|
16
|
+
/// JSON-encoded theme object (see ThemeOptions in types.ts).
|
|
17
|
+
RCT_EXPORT_VIEW_PROPERTY(themeJSON, NSString)
|
|
18
|
+
|
|
19
|
+
// ─── Events ─────────────────────────────────────────────────────────────────
|
|
20
|
+
/// Fires when a link is tapped. Payload: { url: string, isURL: boolean }
|
|
21
|
+
RCT_EXPORT_VIEW_PROPERTY(onLinkPress, RCTDirectEventBlock)
|
|
22
|
+
|
|
23
|
+
/// Fires when an inline image is tapped. Payload: { source: string }
|
|
24
|
+
RCT_EXPORT_VIEW_PROPERTY(onImagePress, RCTDirectEventBlock)
|
|
25
|
+
|
|
26
|
+
/// Fires when lines are selected in a code block.
|
|
27
|
+
/// Payload: { startLine: number, endLine: number, contents: string[], language?: string }
|
|
28
|
+
RCT_EXPORT_VIEW_PROPERTY(onLineSelection, RCTDirectEventBlock)
|
|
29
|
+
|
|
30
|
+
/// Fires when the intrinsic content height changes.
|
|
31
|
+
/// Payload: { contentSize: { width: number, height: number } }
|
|
32
|
+
RCT_EXPORT_VIEW_PROPERTY(onContentSizeChange, RCTDirectEventBlock)
|
|
33
|
+
|
|
34
|
+
@end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import React
|
|
2
|
+
import UIKit
|
|
3
|
+
|
|
4
|
+
/// Old Architecture view manager.
|
|
5
|
+
/// The ObjC bridge in RNMarkdownViewManager.m exports props and this class.
|
|
6
|
+
@objc(RNMarkdownViewManager)
|
|
7
|
+
final class RNMarkdownViewManager: RCTViewManager {
|
|
8
|
+
|
|
9
|
+
override func view() -> UIView! {
|
|
10
|
+
RNMarkdownView()
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
override static func requiresMainQueueSetup() -> Bool {
|
|
14
|
+
true
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bridging header for Swift ↔ Objective-C interop within this pod.
|
|
3
|
+
*
|
|
4
|
+
* The CocoaPods build system picks up SWIFT_OBJC_BRIDGING_HEADER via
|
|
5
|
+
* the pod_target_xcconfig in the podspec and makes these React Native
|
|
6
|
+
* Objective-C headers visible to all Swift source files in the pod.
|
|
7
|
+
*/
|
|
8
|
+
#import <React/RCTViewManager.h>
|
|
9
|
+
#import <React/RCTBridgeModule.h>
|
|
10
|
+
#import <React/RCTEventEmitter.h>
|
|
11
|
+
#import <React/RCTView.h>
|
|
12
|
+
#import <React/RCTUIManager.h>
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.MarkdownView = MarkdownView;
|
|
7
|
+
var _react = _interopRequireWildcard(require("react"));
|
|
8
|
+
var _reactNative = require("react-native");
|
|
9
|
+
var _jsxRuntime = require("react/jsx-runtime");
|
|
10
|
+
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
|
|
11
|
+
// ─── Native component handle ──────────────────────────────────────────────────
|
|
12
|
+
|
|
13
|
+
const COMPONENT_NAME = 'RNMarkdownView';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Old Architecture – loaded lazily so non-iOS platforms don't throw on import.
|
|
17
|
+
* New Architecture uses the codegen-generated component automatically when
|
|
18
|
+
* RCT_NEW_ARCH_ENABLED is set at build time.
|
|
19
|
+
*/
|
|
20
|
+
const NativeMarkdownView = _reactNative.Platform.OS === 'ios' ? (0, _reactNative.requireNativeComponent)(COMPONENT_NAME) : null;
|
|
21
|
+
|
|
22
|
+
// ─── Theme serialisation ──────────────────────────────────────────────────────
|
|
23
|
+
|
|
24
|
+
function serializeTheme(theme) {
|
|
25
|
+
if (!theme) return undefined;
|
|
26
|
+
try {
|
|
27
|
+
return JSON.stringify(theme);
|
|
28
|
+
} catch {
|
|
29
|
+
return undefined;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// ─── Component ────────────────────────────────────────────────────────────────
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* `MarkdownView` renders GitHub Flavored Markdown using Apple's native
|
|
37
|
+
* MarkdownView library (tree-sitter syntax highlighting, LaTeX math,
|
|
38
|
+
* unified diff, VoiceOver). iOS 16+ only.
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* ```tsx
|
|
42
|
+
* <MarkdownView markdown="# Hello\n\nSome **bold** text." />
|
|
43
|
+
* ```
|
|
44
|
+
*
|
|
45
|
+
* @example Custom theme
|
|
46
|
+
* ```tsx
|
|
47
|
+
* <MarkdownView
|
|
48
|
+
* markdown={content}
|
|
49
|
+
* theme={{
|
|
50
|
+
* colors: { body: '#1a1a1a', codeBackground: '#f5f5f5' },
|
|
51
|
+
* fonts: { bodySize: 16 },
|
|
52
|
+
* }}
|
|
53
|
+
* />
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
function MarkdownView({
|
|
57
|
+
markdown,
|
|
58
|
+
theme,
|
|
59
|
+
style,
|
|
60
|
+
onLinkPress,
|
|
61
|
+
onImagePress,
|
|
62
|
+
onLineSelection,
|
|
63
|
+
onContentSizeChange
|
|
64
|
+
}) {
|
|
65
|
+
if (_reactNative.Platform.OS !== 'ios' || NativeMarkdownView === null) {
|
|
66
|
+
if (__DEV__) {
|
|
67
|
+
console.warn('[MarkdownView] Only supported on iOS 16+.');
|
|
68
|
+
}
|
|
69
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
70
|
+
style: style
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
75
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(MarkdownViewInner, {
|
|
76
|
+
markdown: markdown,
|
|
77
|
+
theme: theme,
|
|
78
|
+
style: style,
|
|
79
|
+
onLinkPress: onLinkPress,
|
|
80
|
+
onImagePress: onImagePress,
|
|
81
|
+
onLineSelection: onLineSelection,
|
|
82
|
+
onContentSizeChange: onContentSizeChange,
|
|
83
|
+
NativeComponent: NativeMarkdownView
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Split out so hooks run unconditionally (Platform.OS is constant at runtime).
|
|
88
|
+
|
|
89
|
+
function MarkdownViewInner({
|
|
90
|
+
markdown,
|
|
91
|
+
theme,
|
|
92
|
+
style,
|
|
93
|
+
onLinkPress,
|
|
94
|
+
onImagePress,
|
|
95
|
+
onLineSelection,
|
|
96
|
+
onContentSizeChange,
|
|
97
|
+
NativeComponent
|
|
98
|
+
}) {
|
|
99
|
+
const [autoHeight, setAutoHeight] = (0, _react.useState)(undefined);
|
|
100
|
+
const themeJSONRef = (0, _react.useRef)(undefined);
|
|
101
|
+
|
|
102
|
+
// Re-serialize only when theme reference changes.
|
|
103
|
+
themeJSONRef.current = serializeTheme(theme);
|
|
104
|
+
const handleContentSizeChange = (0, _react.useCallback)(e => {
|
|
105
|
+
const {
|
|
106
|
+
height
|
|
107
|
+
} = e.nativeEvent.contentSize;
|
|
108
|
+
if (height > 0) setAutoHeight(height);
|
|
109
|
+
onContentSizeChange?.(e);
|
|
110
|
+
}, [onContentSizeChange]);
|
|
111
|
+
const handleLinkPress = (0, _react.useCallback)(e => {
|
|
112
|
+
onLinkPress?.(e);
|
|
113
|
+
}, [onLinkPress]);
|
|
114
|
+
const handleImagePress = (0, _react.useCallback)(e => {
|
|
115
|
+
onImagePress?.(e);
|
|
116
|
+
}, [onImagePress]);
|
|
117
|
+
const handleLineSelection = (0, _react.useCallback)(e => {
|
|
118
|
+
onLineSelection?.(e);
|
|
119
|
+
}, [onLineSelection]);
|
|
120
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(NativeComponent, {
|
|
121
|
+
markdown: markdown,
|
|
122
|
+
themeJSON: themeJSONRef.current,
|
|
123
|
+
style: [autoHeight !== undefined && styles.autoHeight(autoHeight), style],
|
|
124
|
+
onLinkPress: handleLinkPress,
|
|
125
|
+
onImagePress: handleImagePress,
|
|
126
|
+
onLineSelection: handleLineSelection,
|
|
127
|
+
onContentSizeChange: handleContentSizeChange
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// ─── Styles ───────────────────────────────────────────────────────────────────
|
|
132
|
+
|
|
133
|
+
const styles = {
|
|
134
|
+
/** Applied when the native view has reported its content height. */
|
|
135
|
+
autoHeight: h => ({
|
|
136
|
+
height: h
|
|
137
|
+
})
|
|
138
|
+
};
|
|
139
|
+
//# sourceMappingURL=MarkdownView.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["_react","_interopRequireWildcard","require","_reactNative","_jsxRuntime","e","t","WeakMap","r","n","__esModule","o","i","f","__proto__","default","has","get","set","hasOwnProperty","call","Object","defineProperty","getOwnPropertyDescriptor","COMPONENT_NAME","NativeMarkdownView","Platform","OS","requireNativeComponent","serializeTheme","theme","undefined","JSON","stringify","MarkdownView","markdown","style","onLinkPress","onImagePress","onLineSelection","onContentSizeChange","__DEV__","console","warn","jsx","View","MarkdownViewInner","NativeComponent","autoHeight","setAutoHeight","useState","themeJSONRef","useRef","current","handleContentSizeChange","useCallback","height","nativeEvent","contentSize","handleLinkPress","handleImagePress","handleLineSelection","themeJSON","styles","h"],"sourceRoot":"../../src","sources":["MarkdownView.tsx"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = void 0;
|
|
7
|
+
var _codegenNativeComponent = _interopRequireDefault(require("react-native/Libraries/Utilities/codegenNativeComponent"));
|
|
8
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
9
|
+
/**
|
|
10
|
+
* Codegen spec for the New Architecture (Fabric).
|
|
11
|
+
*
|
|
12
|
+
* Running `react-native codegen` (or the build system) reads this file and
|
|
13
|
+
* generates C++ component descriptors, props structs, and event emitters under
|
|
14
|
+
* build/generated/ios/RNMarkdownViewSpec/.
|
|
15
|
+
*
|
|
16
|
+
* All prop/event types must use the codegen-compatible primitives from
|
|
17
|
+
* react-native/Libraries/Types/CodegenTypes.
|
|
18
|
+
*/
|
|
19
|
+
// ─── Codegen event payload types ─────────────────────────────────────────────
|
|
20
|
+
// ─── Native component props ───────────────────────────────────────────────────
|
|
21
|
+
var _default = exports.default = (0, _codegenNativeComponent.default)('RNMarkdownView');
|
|
22
|
+
//# sourceMappingURL=NativeMarkdownView.js.map
|