@tinglinzh/react-native-markdownview 0.3.0 → 0.5.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/app.plugin.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
module.exports = require('./plugin/index.js');
|
|
@@ -1,13 +1,33 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Old Architecture
|
|
2
|
+
* Old Architecture view manager — pure Objective-C implementation.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* Framework targets don't support bridging headers, so we:
|
|
5
|
+
* 1. Keep this file as ObjC (no bridging header needed).
|
|
6
|
+
* 2. Import the auto-generated Swift header to access RNMarkdownView.
|
|
7
|
+
* 3. Delete the separate RNMarkdownViewManager.swift file.
|
|
8
|
+
*
|
|
9
|
+
* The Swift-generated header is emitted by the compiler as
|
|
10
|
+
* "react_native_markdownview-Swift.h" (pod name, hyphens → underscores).
|
|
7
11
|
*/
|
|
8
12
|
#import <React/RCTViewManager.h>
|
|
13
|
+
#import "react_native_markdownview-Swift.h"
|
|
14
|
+
|
|
15
|
+
@interface RNMarkdownViewManager : RCTViewManager
|
|
16
|
+
@end
|
|
17
|
+
|
|
18
|
+
@implementation RNMarkdownViewManager
|
|
19
|
+
|
|
20
|
+
RCT_EXPORT_MODULE()
|
|
21
|
+
|
|
22
|
+
- (UIView *)view
|
|
23
|
+
{
|
|
24
|
+
return [[RNMarkdownView alloc] init];
|
|
25
|
+
}
|
|
9
26
|
|
|
10
|
-
|
|
27
|
+
+ (BOOL)requiresMainQueueSetup
|
|
28
|
+
{
|
|
29
|
+
return YES;
|
|
30
|
+
}
|
|
11
31
|
|
|
12
32
|
// ─── Content ────────────────────────────────────────────────────────────────
|
|
13
33
|
/// Raw markdown string.
|
|
@@ -24,11 +44,11 @@ RCT_EXPORT_VIEW_PROPERTY(onLinkPress, RCTDirectEventBlock)
|
|
|
24
44
|
RCT_EXPORT_VIEW_PROPERTY(onImagePress, RCTDirectEventBlock)
|
|
25
45
|
|
|
26
46
|
/// Fires when lines are selected in a code block.
|
|
27
|
-
/// Payload: { startLine: number, endLine: number, contents: string
|
|
47
|
+
/// Payload: { startLine: number, endLine: number, contents: string, language: string }
|
|
28
48
|
RCT_EXPORT_VIEW_PROPERTY(onLineSelection, RCTDirectEventBlock)
|
|
29
49
|
|
|
30
50
|
/// Fires when the intrinsic content height changes.
|
|
31
|
-
/// Payload: {
|
|
51
|
+
/// Payload: { width: number, height: number }
|
|
32
52
|
RCT_EXPORT_VIEW_PROPERTY(onContentSizeChange, RCTDirectEventBlock)
|
|
33
53
|
|
|
34
54
|
@end
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tinglinzh/react-native-markdownview",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "React Native wrapper for MarkdownView — native iOS/macOS markdown rendering with GFM, syntax highlighting, LaTeX math, and unified diff support",
|
|
5
5
|
"main": "lib/commonjs/index",
|
|
6
6
|
"module": "lib/module/index",
|
|
@@ -14,10 +14,13 @@
|
|
|
14
14
|
"types": "./lib/typescript/src/index.d.ts"
|
|
15
15
|
}
|
|
16
16
|
},
|
|
17
|
+
"plugin": "app.plugin.js",
|
|
17
18
|
"files": [
|
|
18
19
|
"src",
|
|
19
20
|
"lib",
|
|
20
21
|
"ios",
|
|
22
|
+
"plugin",
|
|
23
|
+
"app.plugin.js",
|
|
21
24
|
"react-native-markdownview.podspec",
|
|
22
25
|
"Package.swift"
|
|
23
26
|
],
|
|
@@ -37,9 +40,15 @@
|
|
|
37
40
|
"author": "",
|
|
38
41
|
"license": "MIT",
|
|
39
42
|
"peerDependencies": {
|
|
43
|
+
"@expo/config-plugins": ">=7.0.0",
|
|
40
44
|
"react": "*",
|
|
41
45
|
"react-native": "*"
|
|
42
46
|
},
|
|
47
|
+
"peerDependenciesMeta": {
|
|
48
|
+
"@expo/config-plugins": {
|
|
49
|
+
"optional": true
|
|
50
|
+
}
|
|
51
|
+
},
|
|
43
52
|
"devDependencies": {
|
|
44
53
|
"@types/react": "^18.3.28",
|
|
45
54
|
"react": "18.3.1",
|
package/plugin/index.js
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Expo Config Plugin — adds MarkdownView as an SPM dependency to the
|
|
5
|
+
* host app's Xcode project during `expo prebuild`.
|
|
6
|
+
*
|
|
7
|
+
* Without this step the pod can't compile `import MarkdownView` because
|
|
8
|
+
* CocoaPods has no way to pull in Swift Package Manager-only packages.
|
|
9
|
+
*
|
|
10
|
+
* Usage in app.config.ts / app.json:
|
|
11
|
+
* plugins: ['@tinglinzh/react-native-markdownview']
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
const { withXcodeProject } = require('@expo/config-plugins');
|
|
15
|
+
const crypto = require('crypto');
|
|
16
|
+
|
|
17
|
+
const MARKDOWNVIEW_REPO = 'https://github.com/HumanInterfaceDesign/MarkdownView';
|
|
18
|
+
const MARKDOWNVIEW_BRANCH = 'main';
|
|
19
|
+
const PRODUCT_NAME = 'MarkdownView';
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Deterministic 24-char uppercase hex UUID derived from a seed string.
|
|
23
|
+
* Using a fixed seed means `prebuild` is idempotent — re-running it won't
|
|
24
|
+
* add duplicate entries to the pbxproj file.
|
|
25
|
+
*/
|
|
26
|
+
function uuid(seed) {
|
|
27
|
+
return crypto.createHash('sha256').update(seed).digest('hex').toUpperCase().slice(0, 24);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const PKG_REF_UUID = uuid('RNMarkdownView-XCRemoteSwiftPackageReference');
|
|
31
|
+
const PROD_DEP_UUID = uuid('RNMarkdownView-XCSwiftPackageProductDependency');
|
|
32
|
+
const BUILD_FILE_UUID = uuid('RNMarkdownView-PBXBuildFile');
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* @param {import('@expo/config-plugins').ExpoConfig} config
|
|
36
|
+
*/
|
|
37
|
+
const withMarkdownViewSPM = (config) => {
|
|
38
|
+
return withXcodeProject(config, (modConfig) => {
|
|
39
|
+
const project = modConfig.modResults;
|
|
40
|
+
const pbx = project.hash.project.objects;
|
|
41
|
+
|
|
42
|
+
// ── Guard: already added? ──────────────────────────────────────────────
|
|
43
|
+
const existingRefs = pbx['XCRemoteSwiftPackageReference'] || {};
|
|
44
|
+
const alreadyAdded = Object.values(existingRefs).some(
|
|
45
|
+
(ref) =>
|
|
46
|
+
ref &&
|
|
47
|
+
typeof ref === 'object' &&
|
|
48
|
+
typeof ref.repositoryURL === 'string' &&
|
|
49
|
+
ref.repositoryURL.includes('MarkdownView'),
|
|
50
|
+
);
|
|
51
|
+
if (alreadyAdded) return modConfig;
|
|
52
|
+
|
|
53
|
+
// ── 1. XCRemoteSwiftPackageReference ──────────────────────────────────
|
|
54
|
+
pbx['XCRemoteSwiftPackageReference'] = pbx['XCRemoteSwiftPackageReference'] || {};
|
|
55
|
+
pbx['XCRemoteSwiftPackageReference'][PKG_REF_UUID] = {
|
|
56
|
+
isa: 'XCRemoteSwiftPackageReference',
|
|
57
|
+
repositoryURL: `"${MARKDOWNVIEW_REPO}"`,
|
|
58
|
+
requirement: { branch: MARKDOWNVIEW_BRANCH, kind: 'branch' },
|
|
59
|
+
};
|
|
60
|
+
pbx['XCRemoteSwiftPackageReference'][`${PKG_REF_UUID}_comment`] =
|
|
61
|
+
`XCRemoteSwiftPackageReference "${PRODUCT_NAME}"`;
|
|
62
|
+
|
|
63
|
+
// ── 2. XCSwiftPackageProductDependency ────────────────────────────────
|
|
64
|
+
pbx['XCSwiftPackageProductDependency'] = pbx['XCSwiftPackageProductDependency'] || {};
|
|
65
|
+
pbx['XCSwiftPackageProductDependency'][PROD_DEP_UUID] = {
|
|
66
|
+
isa: 'XCSwiftPackageProductDependency',
|
|
67
|
+
package: PKG_REF_UUID,
|
|
68
|
+
productName: PRODUCT_NAME,
|
|
69
|
+
};
|
|
70
|
+
pbx['XCSwiftPackageProductDependency'][`${PROD_DEP_UUID}_comment`] = PRODUCT_NAME;
|
|
71
|
+
|
|
72
|
+
// ── 3. PBXBuildFile ───────────────────────────────────────────────────
|
|
73
|
+
pbx['PBXBuildFile'] = pbx['PBXBuildFile'] || {};
|
|
74
|
+
pbx['PBXBuildFile'][BUILD_FILE_UUID] = {
|
|
75
|
+
isa: 'PBXBuildFile',
|
|
76
|
+
productRef: PROD_DEP_UUID,
|
|
77
|
+
};
|
|
78
|
+
pbx['PBXBuildFile'][`${BUILD_FILE_UUID}_comment`] = `${PRODUCT_NAME} in Frameworks`;
|
|
79
|
+
|
|
80
|
+
// ── 4. PBXProject.packageReferences ──────────────────────────────────
|
|
81
|
+
const projectSection = pbx['PBXProject'] || {};
|
|
82
|
+
const projectObj = Object.values(projectSection).find(
|
|
83
|
+
(v) => v && typeof v === 'object' && v.isa === 'PBXProject',
|
|
84
|
+
);
|
|
85
|
+
if (projectObj) {
|
|
86
|
+
projectObj.packageReferences = projectObj.packageReferences || [];
|
|
87
|
+
if (!projectObj.packageReferences.some((r) => r.value === PKG_REF_UUID)) {
|
|
88
|
+
projectObj.packageReferences.push({
|
|
89
|
+
value: PKG_REF_UUID,
|
|
90
|
+
comment: `XCRemoteSwiftPackageReference "${PRODUCT_NAME}"`,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// ── 5. Add to the main app target ─────────────────────────────────────
|
|
96
|
+
const targetName = modConfig.modRequest.projectName;
|
|
97
|
+
const nativeTargets = pbx['PBXNativeTarget'] || {};
|
|
98
|
+
|
|
99
|
+
for (const [, target] of Object.entries(nativeTargets)) {
|
|
100
|
+
if (!target || typeof target !== 'object') continue;
|
|
101
|
+
|
|
102
|
+
// pbxproj stores names with surrounding quotes; handle both forms.
|
|
103
|
+
const name = typeof target.name === 'string'
|
|
104
|
+
? target.name.replace(/^"|"$/g, '')
|
|
105
|
+
: '';
|
|
106
|
+
if (name !== targetName) continue;
|
|
107
|
+
|
|
108
|
+
// packageProductDependencies
|
|
109
|
+
target.packageProductDependencies = target.packageProductDependencies || [];
|
|
110
|
+
if (!target.packageProductDependencies.some((d) => d.value === PROD_DEP_UUID)) {
|
|
111
|
+
target.packageProductDependencies.push({
|
|
112
|
+
value: PROD_DEP_UUID,
|
|
113
|
+
comment: PRODUCT_NAME,
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Add build file to PBXFrameworksBuildPhase
|
|
118
|
+
for (const phaseRef of target.buildPhases || []) {
|
|
119
|
+
const frameworksSection = pbx['PBXFrameworksBuildPhase'] || {};
|
|
120
|
+
const phase = frameworksSection[phaseRef.value];
|
|
121
|
+
if (!phase) continue;
|
|
122
|
+
|
|
123
|
+
phase.files = phase.files || [];
|
|
124
|
+
if (!phase.files.some((f) => f.value === BUILD_FILE_UUID)) {
|
|
125
|
+
phase.files.push({
|
|
126
|
+
value: BUILD_FILE_UUID,
|
|
127
|
+
comment: `${PRODUCT_NAME} in Frameworks`,
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
break;
|
|
131
|
+
}
|
|
132
|
+
break;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return modConfig;
|
|
136
|
+
});
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
module.exports = withMarkdownViewSPM;
|
|
@@ -15,11 +15,11 @@ Pod::Spec.new do |s|
|
|
|
15
15
|
s.source_files = "ios/**/*.{h,m,mm,swift}"
|
|
16
16
|
s.swift_version = "5.9"
|
|
17
17
|
|
|
18
|
-
#
|
|
18
|
+
# Allow the Swift compiler to find the MarkdownView module when it is added
|
|
19
|
+
# to the host app via Xcode's Swift Package integration.
|
|
20
|
+
# Framework targets cannot use bridging headers; ObjC↔Swift interop is handled
|
|
21
|
+
# via the auto-generated "-Swift.h" header imported in RNMarkdownViewManager.m.
|
|
19
22
|
s.pod_target_xcconfig = {
|
|
20
|
-
"SWIFT_OBJC_BRIDGING_HEADER" => "$(PODS_TARGET_SRCROOT)/ios/react-native-markdownview-Bridging-Header.h",
|
|
21
|
-
# Allow the Swift compiler to find the MarkdownView Swift module when it is
|
|
22
|
-
# added to the host app via SPM (Xcode embeds SPM-built modules here).
|
|
23
23
|
"SWIFT_INCLUDE_PATHS" => "$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/PackageFrameworks/**",
|
|
24
24
|
}
|
|
25
25
|
|
|
@@ -1,16 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
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>
|