Skip to content

Commit 86f7b44

Browse files
authored
Merge pull request #1 from software-mansion-labs/@hryhoriiK97/ios/implement-basic-ios-markdown-component
[ios] Implement basic iOS markdown rendering
2 parents ad51780 + d71c6ff commit 86f7b44

26 files changed

Lines changed: 1637 additions & 153 deletions

.github/workflows/ci.yml

Lines changed: 107 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -57,110 +57,110 @@ jobs:
5757
- name: Build package
5858
run: yarn prepare
5959

60-
build-android:
61-
runs-on: ubuntu-latest
62-
63-
env:
64-
TURBO_CACHE_DIR: .turbo/android
65-
66-
steps:
67-
- name: Checkout
68-
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
69-
70-
- name: Setup
71-
uses: ./.github/actions/setup
72-
73-
- name: Cache turborepo for Android
74-
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
75-
with:
76-
path: ${{ env.TURBO_CACHE_DIR }}
77-
key: ${{ runner.os }}-turborepo-android-${{ hashFiles('yarn.lock') }}
78-
restore-keys: |
79-
${{ runner.os }}-turborepo-android-
80-
81-
- name: Check turborepo cache for Android
82-
run: |
83-
TURBO_CACHE_STATUS=$(node -p "($(yarn turbo run build:android --cache-dir="${{ env.TURBO_CACHE_DIR }}" --dry=json)).tasks.find(t => t.task === 'build:android').cache.status")
84-
85-
if [[ $TURBO_CACHE_STATUS == "HIT" ]]; then
86-
echo "turbo_cache_hit=1" >> $GITHUB_ENV
87-
fi
88-
89-
- name: Install JDK
90-
if: env.turbo_cache_hit != 1
91-
uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1
92-
with:
93-
distribution: 'zulu'
94-
java-version: '17'
95-
96-
- name: Finalize Android SDK
97-
if: env.turbo_cache_hit != 1
98-
run: |
99-
/bin/bash -c "yes | $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager --licenses > /dev/null"
100-
101-
- name: Cache Gradle
102-
if: env.turbo_cache_hit != 1
103-
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
104-
with:
105-
path: |
106-
~/.gradle/wrapper
107-
~/.gradle/caches
108-
key: ${{ runner.os }}-gradle-${{ hashFiles('example/android/gradle/wrapper/gradle-wrapper.properties') }}
109-
restore-keys: |
110-
${{ runner.os }}-gradle-
111-
112-
- name: Build example for Android
113-
env:
114-
JAVA_OPTS: "-XX:MaxHeapSize=6g"
115-
run: |
116-
yarn turbo run build:android --cache-dir="${{ env.TURBO_CACHE_DIR }}"
117-
118-
build-ios:
119-
runs-on: macos-latest
120-
121-
env:
122-
XCODE_VERSION: 16.3
123-
TURBO_CACHE_DIR: .turbo/ios
124-
RCT_USE_RN_DEP: 1
125-
RCT_USE_PREBUILT_RNCORE: 1
126-
127-
steps:
128-
- name: Checkout
129-
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
130-
131-
- name: Setup
132-
uses: ./.github/actions/setup
133-
134-
- name: Cache turborepo for iOS
135-
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
136-
with:
137-
path: ${{ env.TURBO_CACHE_DIR }}
138-
key: ${{ runner.os }}-turborepo-ios-${{ hashFiles('yarn.lock') }}
139-
restore-keys: |
140-
${{ runner.os }}-turborepo-ios-
141-
142-
- name: Check turborepo cache for iOS
143-
run: |
144-
TURBO_CACHE_STATUS=$(node -p "($(yarn turbo run build:ios --cache-dir="${{ env.TURBO_CACHE_DIR }}" --dry=json)).tasks.find(t => t.task === 'build:ios').cache.status")
145-
146-
if [[ $TURBO_CACHE_STATUS == "HIT" ]]; then
147-
echo "turbo_cache_hit=1" >> $GITHUB_ENV
148-
fi
149-
150-
- name: Use appropriate Xcode version
151-
if: env.turbo_cache_hit != 1
152-
uses: maxim-lobanov/setup-xcode@60606e260d2fc5762a71e64e74b2174e8ea3c8bd # v1.6.0
153-
with:
154-
xcode-version: ${{ env.XCODE_VERSION }}
155-
156-
- name: Install cocoapods
157-
if: env.turbo_cache_hit != 1 && steps.cocoapods-cache.outputs.cache-hit != 'true'
158-
run: |
159-
cd example
160-
bundle install
161-
bundle exec pod repo update --verbose
162-
bundle exec pod install --project-directory=ios
163-
164-
- name: Build example for iOS
165-
run: |
166-
yarn turbo run build:ios --cache-dir="${{ env.TURBO_CACHE_DIR }}"
60+
# build-android:
61+
# runs-on: ubuntu-latest
62+
63+
# env:
64+
# TURBO_CACHE_DIR: .turbo/android
65+
66+
# steps:
67+
# - name: Checkout
68+
# uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
69+
70+
# - name: Setup
71+
# uses: ./.github/actions/setup
72+
73+
# - name: Cache turborepo for Android
74+
# uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
75+
# with:
76+
# path: ${{ env.TURBO_CACHE_DIR }}
77+
# key: ${{ runner.os }}-turborepo-android-${{ hashFiles('yarn.lock') }}
78+
# restore-keys: |
79+
# ${{ runner.os }}-turborepo-android-
80+
81+
# - name: Check turborepo cache for Android
82+
# run: |
83+
# TURBO_CACHE_STATUS=$(node -p "($(yarn turbo run build:android --cache-dir="${{ env.TURBO_CACHE_DIR }}" --dry=json)).tasks.find(t => t.task === 'build:android').cache.status")
84+
85+
# if [[ $TURBO_CACHE_STATUS == "HIT" ]]; then
86+
# echo "turbo_cache_hit=1" >> $GITHUB_ENV
87+
# fi
88+
89+
# - name: Install JDK
90+
# if: env.turbo_cache_hit != 1
91+
# uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1
92+
# with:
93+
# distribution: 'zulu'
94+
# java-version: '17'
95+
96+
# - name: Finalize Android SDK
97+
# if: env.turbo_cache_hit != 1
98+
# run: |
99+
# /bin/bash -c "yes | $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager --licenses > /dev/null"
100+
101+
# - name: Cache Gradle
102+
# if: env.turbo_cache_hit != 1
103+
# uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
104+
# with:
105+
# path: |
106+
# ~/.gradle/wrapper
107+
# ~/.gradle/caches
108+
# key: ${{ runner.os }}-gradle-${{ hashFiles('example/android/gradle/wrapper/gradle-wrapper.properties') }}
109+
# restore-keys: |
110+
# ${{ runner.os }}-gradle-
111+
112+
# - name: Build example for Android
113+
# env:
114+
# JAVA_OPTS: '-XX:MaxHeapSize=6g'
115+
# run: |
116+
# yarn turbo run build:android --cache-dir="${{ env.TURBO_CACHE_DIR }}"
117+
118+
# build-ios:
119+
# runs-on: macos-latest
120+
121+
# env:
122+
# XCODE_VERSION: 16.3
123+
# TURBO_CACHE_DIR: .turbo/ios
124+
# RCT_USE_RN_DEP: 1
125+
# RCT_USE_PREBUILT_RNCORE: 1
126+
127+
# steps:
128+
# - name: Checkout
129+
# uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
130+
131+
# - name: Setup
132+
# uses: ./.github/actions/setup
133+
134+
# - name: Cache turborepo for iOS
135+
# uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
136+
# with:
137+
# path: ${{ env.TURBO_CACHE_DIR }}
138+
# key: ${{ runner.os }}-turborepo-ios-${{ hashFiles('yarn.lock') }}
139+
# restore-keys: |
140+
# ${{ runner.os }}-turborepo-ios-
141+
142+
# - name: Check turborepo cache for iOS
143+
# run: |
144+
# TURBO_CACHE_STATUS=$(node -p "($(yarn turbo run build:ios --cache-dir="${{ env.TURBO_CACHE_DIR }}" --dry=json)).tasks.find(t => t.task === 'build:ios').cache.status")
145+
146+
# if [[ $TURBO_CACHE_STATUS == "HIT" ]]; then
147+
# echo "turbo_cache_hit=1" >> $GITHUB_ENV
148+
# fi
149+
150+
# - name: Use appropriate Xcode version
151+
# if: env.turbo_cache_hit != 1
152+
# uses: maxim-lobanov/setup-xcode@60606e260d2fc5762a71e64e74b2174e8ea3c8bd # v1.6.0
153+
# with:
154+
# xcode-version: ${{ env.XCODE_VERSION }}
155+
156+
# - name: Install cocoapods
157+
# if: env.turbo_cache_hit != 1 && steps.cocoapods-cache.outputs.cache-hit != 'true'
158+
# run: |
159+
# cd example
160+
# bundle install
161+
# bundle exec pod repo update --verbose
162+
# bundle exec pod install --project-directory=ios
163+
164+
# - name: Build example for iOS
165+
# run: |
166+
# yarn turbo run build:ios --cache-dir="${{ env.TURBO_CACHE_DIR }}"

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[submodule "shared/MD4C"]
2+
path = shared/MD4C
3+
url = https://github.com/mity/md4c.git

CONTRIBUTING.md

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,27 @@ This project is a monorepo managed using [Yarn workspaces](https://yarnpkg.com/f
1313

1414
To get started with the project, make sure you have the correct version of [Node.js](https://nodejs.org/) installed. See the [`.nvmrc`](./.nvmrc) file for the version used in this project.
1515

16-
Run `yarn` in the root directory to install the required dependencies for each package:
16+
### Cloning the Repository
17+
18+
When cloning this repository, make sure to include submodules:
1719

1820
```sh
21+
# Clone with submodules (recommended)
22+
git clone --recurse-submodules https://github.com/software-mansion-labs/react-native-rich-text.git
23+
24+
# Or if you've already cloned without submodules:
25+
git clone https://github.com/software-mansion-labs/react-native-rich-text.git
26+
cd react-native-rich-text
27+
git submodule add https://github.com/mity/md4c.git shared/MD4C
28+
```
29+
30+
## Initial Setup
31+
32+
This project uses git submodules for native dependencies. You need to initialize the submodules before installing dependencies:
33+
34+
```sh
35+
36+
# Install dependencies
1937
yarn
2038
```
2139

@@ -76,6 +94,20 @@ Remember to add tests for your change if possible. Run the unit tests by:
7694
yarn test
7795
```
7896

97+
### Testing MD4C Integration
98+
99+
This project includes native markdown parsing capabilities using the MD4C library. To test the MD4C integration:
100+
101+
```sh
102+
# Run MD4C integration tests
103+
./scripts/test-md4c.sh
104+
```
105+
106+
This will test:
107+
108+
- MD4C compilation and execution
109+
- iOS podspec configuration
110+
79111
### Commit message convention
80112

81113
We follow the [conventional commits specification](https://www.conventionalcommits.org/en) for our commit messages:
@@ -119,6 +151,10 @@ The `package.json` file contains various scripts for common tasks:
119151
- `yarn example android`: run the example app on Android.
120152
- `yarn example ios`: run the example app on iOS.
121153

154+
Additional scripts for native development:
155+
156+
- `./scripts/test-md4c.sh`: test MD4C integration and native setup.
157+
122158
### Sending a pull request
123159

124160
> **Working on your first pull request?** You can learn how from this _free_ series: [How to Contribute to an Open Source Project on GitHub](https://app.egghead.io/playlists/how-to-contribute-to-an-open-source-project-on-github).

RichText.podspec

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,13 @@ Pod::Spec.new do |s|
1313
s.platforms = { :ios => min_ios_version_supported }
1414
s.source = { :git => "https://github.com/software-mansion-labs/react-native-rich-text.git", :tag => "#{s.version}" }
1515

16-
s.source_files = "ios/**/*.{h,m,mm,cpp}"
16+
s.source_files = "ios/**/*.{h,m,mm,cpp}", "shared/MD4C/src/md4c.c", "shared/MD4C/src/entity.c"
1717
s.private_header_files = "ios/**/*.h"
18+
19+
# Set header search paths to submodule
20+
s.pod_target_xcconfig = {
21+
'HEADER_SEARCH_PATHS' => '$(PODS_TARGET_SRCROOT)/shared/MD4C/src'
22+
}
1823

1924

2025
install_modules_dependencies(s)

example/ios/Podfile.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2673,7 +2673,7 @@ SPEC CHECKSUMS:
26732673
ReactAppDependencyProvider: 3eb9096cb139eb433965693bbe541d96eb3d3ec9
26742674
ReactCodegen: 4d203eddf6f977caa324640a20f92e70408d648b
26752675
ReactCommon: ce5d4226dfaf9d5dacbef57b4528819e39d3a120
2676-
RichText: bc45c6536e044f3c57b4f4f0aaa0dab911395d2f
2676+
RichText: c5ea51a2a21a79d2b3e670f73a75c25627a31181
26772677
SocketRocket: d4aabe649be1e368d1318fdf28a022d714d65748
26782678
Yoga: 11c9686a21e2cd82a094a723649d9f4507200fb0
26792679

example/src/App.tsx

Lines changed: 64 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,77 @@
1-
import { View, StyleSheet } from 'react-native';
1+
import {
2+
StyleSheet,
3+
ScrollView,
4+
SafeAreaView,
5+
Alert,
6+
Linking,
7+
} from 'react-native';
28
import { RichTextView } from 'react-native-rich-text';
9+
import type { HeaderConfig } from 'react-native-rich-text';
10+
11+
const HEADER_CONFIG: HeaderConfig = {
12+
scale: 2.0,
13+
isBold: true,
14+
};
15+
16+
const sampleMarkdown = `#### Welcome to the React Native Markdown component!
17+
18+
This is a simple text with links.
19+
20+
Check out this [link to React Native](https://reactnative.dev) and this [GitHub repository](https://github.com/facebook/react-native).
21+
22+
Built with ❤️ using React Native Fabric Architecture`;
323

424
export default function App() {
25+
const handleLinkPress = (event: { nativeEvent: { url: string } }) => {
26+
const { url } = event.nativeEvent;
27+
Alert.alert('Link Pressed!', `You tapped on: ${url}`, [
28+
{
29+
text: 'Open in Browser',
30+
onPress: () => {
31+
Linking.openURL(url);
32+
},
33+
},
34+
{
35+
text: 'Cancel',
36+
style: 'cancel',
37+
},
38+
]);
39+
};
40+
541
return (
6-
<View style={styles.container}>
7-
<RichTextView color="#32a852" style={styles.box} />
8-
</View>
42+
<SafeAreaView style={styles.container}>
43+
<ScrollView
44+
style={styles.scrollView}
45+
contentContainerStyle={styles.content}
46+
>
47+
<RichTextView
48+
markdown={sampleMarkdown}
49+
style={styles.markdown}
50+
fontSize={18}
51+
fontFamily="Helvetica"
52+
headerConfig={HEADER_CONFIG}
53+
textColor="#F54927"
54+
onLinkPress={handleLinkPress}
55+
/>
56+
</ScrollView>
57+
</SafeAreaView>
958
);
1059
}
1160

1261
const styles = StyleSheet.create({
1362
container: {
1463
flex: 1,
15-
alignItems: 'center',
16-
justifyContent: 'center',
1764
},
18-
box: {
19-
width: 60,
20-
height: 60,
21-
marginVertical: 20,
65+
scrollView: {
66+
flex: 1,
67+
},
68+
content: {
69+
padding: 20,
70+
},
71+
markdown: {
72+
flex: 1,
73+
padding: 10,
74+
borderRadius: 8,
75+
minHeight: 250,
2276
},
2377
});

0 commit comments

Comments
 (0)