Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 104 additions & 4 deletions apps/example/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1878,6 +1878,98 @@ PODS:
- ReactCommon/turbomodule/core
- ReactNativeDependencies
- Yoga
- RNScreens (4.24.0):
- hermes-engine
- RCTRequired
- RCTTypeSafety
- React-Core
- React-Core-prebuilt
- React-debug
- React-Fabric
- React-featureflags
- React-graphics
- React-ImageManager
- React-jsi
- React-NativeModulesApple
- React-RCTFabric
- React-RCTImage
- React-renderercss
- React-rendererdebug
- React-utils
- ReactCodegen
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- ReactNativeDependencies
- RNScreens/common (= 4.24.0)
- Yoga
- RNScreens/common (4.24.0):
- hermes-engine
- RCTRequired
- RCTTypeSafety
- React-Core
- React-Core-prebuilt
- React-debug
- React-Fabric
- React-featureflags
- React-graphics
- React-ImageManager
- React-jsi
- React-NativeModulesApple
- React-RCTFabric
- React-RCTImage
- React-renderercss
- React-rendererdebug
- React-utils
- ReactCodegen
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- ReactNativeDependencies
- Yoga
- RNSVG (15.15.4):
- hermes-engine
- RCTRequired
- RCTTypeSafety
- React-Core
- React-Core-prebuilt
- React-debug
- React-Fabric
- React-featureflags
- React-graphics
- React-ImageManager
- React-jsi
- React-NativeModulesApple
- React-RCTFabric
- React-renderercss
- React-rendererdebug
- React-utils
- ReactCodegen
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- ReactNativeDependencies
- RNSVG/common (= 15.15.4)
- Yoga
- RNSVG/common (15.15.4):
- hermes-engine
- RCTRequired
- RCTTypeSafety
- React-Core
- React-Core-prebuilt
- React-debug
- React-Fabric
- React-featureflags
- React-graphics
- React-ImageManager
- React-jsi
- React-NativeModulesApple
- React-RCTFabric
- React-renderercss
- React-rendererdebug
- React-utils
- ReactCodegen
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- ReactNativeDependencies
- Yoga
- Yoga (0.0.0)

DEPENDENCIES:
Expand Down Expand Up @@ -1956,6 +2048,8 @@ DEPENDENCIES:
- ReactCommon/turbomodule/core (from `../node_modules/react-native/ReactCommon`)
- ReactNativeDependencies (from `../node_modules/react-native/third-party-podspecs/ReactNativeDependencies.podspec`)
- ReactNativeEnrichedMarkdown (from `../../..`)
- RNScreens (from `../node_modules/react-native-screens`)
- RNSVG (from `../node_modules/react-native-svg`)
- Yoga (from `../node_modules/react-native/ReactCommon/yoga`)

SPEC REPOS:
Expand Down Expand Up @@ -2112,12 +2206,16 @@ EXTERNAL SOURCES:
:podspec: "../node_modules/react-native/third-party-podspecs/ReactNativeDependencies.podspec"
ReactNativeEnrichedMarkdown:
:path: "../../.."
RNScreens:
:path: "../node_modules/react-native-screens"
RNSVG:
:path: "../node_modules/react-native-svg"
Yoga:
:path: "../node_modules/react-native/ReactCommon/yoga"

SPEC CHECKSUMS:
FBLazyVector: e97c19a5a442429d1988f182a1940fb08df514da
hermes-engine: b0f9c82a51be8e938eb979ada628323e1e093f1d
hermes-engine: fe39e9e5fd85771a2284437c03070d229bd86364
iosMath: f7a6cbadf9d836d2149c2a84c435b1effc244cba
RCTDeprecation: af44b104091a34482596cd9bd7e8d90c4e9b4bd7
RCTRequired: bb77b070f75f53398ce43c0aaaa58337cebe2bf6
Expand All @@ -2127,7 +2225,7 @@ SPEC CHECKSUMS:
React: 1ba7d364ade7d883a1ec055bfc3606f35fdee17b
React-callinvoker: bc2a26f8d84fb01f003fc6de6c9337b64715f95b
React-Core: 7840d3a80b43a95c5e80ef75146bd70925ebab0f
React-Core-prebuilt: 3dc04e91547fc0f260f4b84c12da0f672b813862
React-Core-prebuilt: 5c6d4841913c2f9c34dc045ec2821a618e7ccf66
React-CoreModules: 2eb010400b63b89e53a324ffb3c112e4c7c3ce42
React-cxxreact: a558e92199d26f145afa9e62c4233cf8e7950efe
React-debug: 755200a6e7f5e6e0a40ff8d215493d43cce285fc
Expand Down Expand Up @@ -2189,10 +2287,12 @@ SPEC CHECKSUMS:
ReactAppDependencyProvider: e96e93b493d8d86eeaee3e590ba0be53f6abe46f
ReactCodegen: 797de5178718324c6eba3327b07f9a423fbd5787
ReactCommon: 07572bf9e687c8a52fbe4a3641e9e3a1a477c78e
ReactNativeDependencies: 44f7326a697de7f6c8629036b1a4689f0e64c684
ReactNativeDependencies: 07a3c3c91a68225c545417dde4202a570b8b401d
ReactNativeEnrichedMarkdown: e6fea750b1ca4cbd853c1c78de9bd1ccb638ab77
RNScreens: 6cb648bdad8fe9bee9259fe144df95b6d1d5b707
RNSVG: c69f7709226108f5eb89b5aa8833c17a36345468
Yoga: c0b3f2c7e8d3e327e450223a2414ca3fa296b9a2

PODFILE CHECKSUM: 9c5417fc84515945aa2357a49779fde55434ae62

COCOAPODS: 1.16.2
COCOAPODS: 1.15.2
26 changes: 15 additions & 11 deletions apps/example/metro.config.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
const path = require('path');
const { getDefaultConfig } = require('@react-native/metro-config');
const { getDefaultConfig, mergeConfig } = require('@react-native/metro-config');
const { withMetroConfig } = require('react-native-monorepo-config');

const root = path.resolve(__dirname, '../..');
const defaultConfig = getDefaultConfig(__dirname);
const { assetExts, sourceExts } = defaultConfig.resolver;

/**
* Metro configuration
* https://facebook.github.io/metro/docs/configuration
*
* @type {import('metro-config').MetroConfig}
*/
module.exports = withMetroConfig(getDefaultConfig(__dirname), {
root,
dirname: __dirname,
});
module.exports = withMetroConfig(
mergeConfig(defaultConfig, {
transformer: {
babelTransformerPath: require.resolve('react-native-svg-transformer'),
},
resolver: {
assetExts: assetExts.filter((ext) => ext !== 'svg'),
sourceExts: [...sourceExts, 'svg'],
},
}),
{ root, dirname: __dirname }
);
9 changes: 7 additions & 2 deletions apps/example/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,13 @@
},
"dependencies": {
"@react-native/new-app-screen": "0.84.1",
"@react-navigation/native": "^7.2.2",
"@react-navigation/native-stack": "^7.14.12",
"react": "19.2.3",
"react-native": "0.84.1",
"react-native-safe-area-context": "^5.5.2"
"react-native-safe-area-context": "^5.5.2",
"react-native-screens": "^4.24.0",
"react-native-svg": "^15.15.4"
},
"devDependencies": {
"@babel/core": "^7.25.2",
Expand All @@ -27,7 +31,8 @@
"@react-native/typescript-config": "0.84.1",
"@types/react": "^19.2.0",
"react-native-builder-bob": "^0.40.18",
"react-native-monorepo-config": "^0.3.3"
"react-native-monorepo-config": "^0.3.3",
"react-native-svg-transformer": "^1.5.3"
},
"engines": {
"node": ">= 22.11.0"
Expand Down
185 changes: 48 additions & 137 deletions apps/example/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,142 +1,53 @@
import { useState, useMemo } from 'react';
import {
StyleSheet,
ScrollView,
Alert,
Linking,
Platform,
View,
Text,
} from 'react-native';
import {
EnrichedMarkdownText,
type LinkPressEvent,
} from 'react-native-enriched-markdown';
import { SafeAreaView } from 'react-native-safe-area-context';
import { sampleMarkdown } from './sampleMarkdown';
import { customMarkdownStyle } from './markdownStyles';
import InputScreen from './InputScreen';
import StreamingMarkdownSimulator from './StreamingMarkdownSimulator';

type Screen = 'text' | 'input' | 'stream';
import { NavigationContainer } from '@react-navigation/native';
import { Stack } from './navigation/Stack';
import HomeScreen from './screens/home/HomeScreen';
import PlaygroundScreen from './screens/playground/PlaygroundScreen';
import TextScreen from './screens/text/TextScreen';
import InputScreen from './screens/input/InputScreen';
import StreamingMarkdownSimulator from './screens/streaming/StreamingMarkdownSimulator';

export default function App() {
const [screen, setScreen] = useState<Screen>('input');
const markdownStyle = useMemo(() => customMarkdownStyle, []);

const contextMenuItems = useMemo(
() => [
{
text: 'Summarize with AI',
icon: Platform.OS === 'ios' ? 'sparkles' : undefined,
onPress: ({ text }: { text: string }) => {
Alert.alert('✦ Summarize with AI', `"${text}"`, [
{ text: 'Dismiss', style: 'cancel' },
]);
},
},
{
text: 'Translate',
icon: Platform.OS === 'ios' ? 'globe' : undefined,
onPress: ({ text }: { text: string }) => {
Alert.alert('Translate', `"${text}"`, [
{ text: 'Dismiss', style: 'cancel' },
]);
},
},
],
[]
);

const handleLinkPress = (event: LinkPressEvent) => {
const { url } = event;
Alert.alert('Link Pressed!', `You tapped on: ${url}`, [
{
text: 'Open in Browser',
onPress: () => {
Linking.openURL(url);
},
},
{
text: 'Cancel',
style: 'cancel',
},
]);
};

return (
<SafeAreaView style={styles.root}>
<View style={styles.tabs}>
<Text
style={[styles.tab, screen === 'input' && styles.tabActive]}
onPress={() => setScreen('input')}
>
Input
</Text>
<Text
style={[styles.tab, screen === 'text' && styles.tabActive]}
onPress={() => setScreen('text')}
>
Text
</Text>
<Text
style={[styles.tab, screen === 'stream' && styles.tabActive]}
onPress={() => setScreen('stream')}
>
Stream
</Text>
</View>

{screen === 'input' ? (
<InputScreen />
) : screen === 'stream' ? (
<StreamingMarkdownSimulator />
) : (
<ScrollView
style={styles.scrollView}
contentContainerStyle={styles.content}
>
<EnrichedMarkdownText
flavor="github"
markdown={sampleMarkdown}
onLinkPress={handleLinkPress}
markdownStyle={markdownStyle}
contextMenuItems={contextMenuItems}
selectionColor={Platform.OS === 'ios' ? '#5A52FA' : '#DCDDFE'}
selectionHandleColor="#5A52FA"
/>
</ScrollView>
)}
</SafeAreaView>
<NavigationContainer>
<Stack.Navigator
initialRouteName="Home"
screenOptions={{
headerStyle: {
backgroundColor: '#BEEBD0',
},
headerTintColor: '#001A72',
headerTitleStyle: {
fontWeight: 'bold',
},
headerBackButtonDisplayMode: 'minimal',
}}
>
<Stack.Screen
name="Home"
component={HomeScreen}
options={{ title: 'Enriched Markdown Examples' }}
/>
<Stack.Screen
name="Playground"
component={PlaygroundScreen}
options={{ title: 'Playground' }}
/>
<Stack.Screen
name="Text"
component={TextScreen}
options={{ title: 'Text' }}
/>
<Stack.Screen
name="Input"
component={InputScreen}
options={{ title: 'Input' }}
/>
<Stack.Screen
name="Stream"
component={StreamingMarkdownSimulator}
options={{ title: 'Stream' }}
/>
</Stack.Navigator>
</NavigationContainer>
);
}

const styles = StyleSheet.create({
root: {
flex: 1,
},
tabs: {
flexDirection: 'row',
borderBottomWidth: StyleSheet.hairlineWidth,
borderBottomColor: '#D1D5DB',
},
tab: {
flex: 1,
textAlign: 'center',
paddingVertical: 12,
fontSize: 15,
fontWeight: '500',
color: '#6B7280',
},
tabActive: {
color: '#2563EB',
borderBottomWidth: 2,
borderBottomColor: '#2563EB',
},
scrollView: {
paddingHorizontal: 16,
},
content: {
paddingVertical: 16,
},
});
Loading
Loading