Skip to content
Merged
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
104 changes: 2 additions & 102 deletions examples/0.84/App.tsx
Original file line number Diff line number Diff line change
@@ -1,109 +1,9 @@
import { Button } from '@react-navigation/elements';
import {
NavigationContainer,
NavigationContainerRef,
ParamListBase,
useNavigation,
} from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { useReactNavigationDevTools } from '@rozenite/react-navigation-plugin';
import { useRef } from 'react';
import { View, Text, StyleSheet, Dimensions } from 'react-native';
import Animated, { type CSSAnimationKeyframes } from 'react-native-reanimated';

import Logo from './logo.svg';

const windowWidth = Dimensions.get('window').width;
const logoSize = windowWidth * 0.4;

const breathe: CSSAnimationKeyframes = {
to: {
transform: [{ scale: 1.1 }],
},
};

function HomeScreen() {
const navigation = useNavigation<any>();

return (
<View style={styles.container}>
<Animated.View
animatedProps={{
animationName: breathe,
animationDuration: 1000,
animationTimingFunction: 'ease-in-out',
animationIterationCount: 'infinite',
animationDirection: 'alternate',
}}
>
<Logo width={logoSize} height={logoSize} />
</Animated.View>
<View style={styles.descriptionContainer}>
<Text style={styles.title}>Rollipop</Text>
<Text style={styles.description}>{import.meta.env.ROLLIPOP_DESCRIPTION}</Text>
</View>
<View style={styles.buttonContainer}>
<Button onPress={() => navigation.navigate('get_started')}>Get Started</Button>
</View>
</View>
);
}

function GetStarted() {
return (
<View style={styles.container}>
<View style={styles.descriptionContainer}>
<Text style={styles.title}>Hello, world!</Text>
</View>
</View>
);
}

const RootStack = createNativeStackNavigator();
import { AppNavigator } from './src/navigation/AppNavigator';

export function App() {
const navigationRef = useRef<NavigationContainerRef<ParamListBase>>(null!);

useReactNavigationDevTools({ ref: navigationRef });

return (
<NavigationContainer ref={navigationRef}>
<RootStack.Navigator initialRouteName="home" screenOptions={{ headerShown: false }}>
<RootStack.Screen name="home" component={HomeScreen} />
<RootStack.Screen name="get_started" component={GetStarted} />
</RootStack.Navigator>
</NavigationContainer>
);
return <AppNavigator />;
}

const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: 'white',
gap: 12,
paddingBottom: 36,
},
descriptionContainer: {
alignItems: 'center',
justifyContent: 'center',
gap: 8,
},
buttonContainer: {
paddingVertical: 16,
},
title: {
fontSize: 24,
fontWeight: 'bold',
color: '#222',
},
description: {
fontSize: 16,
color: '#666',
},
});

if (import.meta.hot) {
import.meta.hot.on('custom-server-event', (data) => {
console.log('Received custom server event:', data);
Expand Down
2 changes: 2 additions & 0 deletions examples/0.84/__tests__/App.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ import { App } from '../App';
describe('rollipop/jest-preset — RN integration', () => {
it('renders correctly', async () => {
const instance = render(<App />);
expect(instance.getByText('Rollipop')).toBeTruthy();
expect(instance.getByText('Modern build toolkit for React Native')).toBeTruthy();
expect(instance.getByText('Get Started')).toBeTruthy();
});

it('exposes Platform.OS and Platform.constants via jest-preset NativeModules', () => {
Expand Down
23 changes: 20 additions & 3 deletions examples/0.84/__tests__/navigation.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,32 @@ import { fireEvent, render, screen } from '@testing-library/react-native';
import React from 'react';

import { App } from '../App';
import { runtimeChecks } from '../src/utils/runtimeChecks';

test('pressing "Get Started" navigates to the GetStarted screen', async () => {
test('pressing "Get Started" navigates to the details screen', async () => {
render(<App />);

// Home screen is shown initially with the "Get Started" button.
expect(screen.getByText('Get Started')).toBeTruthy();

fireEvent.press(screen.getByText('Get Started'));

// After navigation, the GetStarted screen renders its title.
expect(await screen.findByText('Hello, world!')).toBeTruthy();
// After navigation, the details screen renders its title.
expect(await screen.findByText('Test cases')).toBeTruthy();
});

test('running the test suites reports all runtime checks as passed', async () => {
render(<App />);

fireEvent.press(screen.getByText('Get Started'));
expect(await screen.findByText('Test cases')).toBeTruthy();

fireEvent.press(screen.getByText('Open Test Suites'));
expect(await screen.findByText('Runtime checks')).toBeTruthy();

fireEvent.press(screen.getByText('Run all checks'));

expect(
await screen.findByText(`${runtimeChecks.length}/${runtimeChecks.length} checks passed`),
).toBeTruthy();
});
79 changes: 79 additions & 0 deletions examples/0.84/src/components/AppButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import type { GestureResponderEvent } from 'react-native';
import { Pressable, StyleSheet, Text } from 'react-native';

import { colors, spacing } from '../theme';

type ButtonVariant = 'primary' | 'secondary' | 'ghost';

type AppButtonProps = {
label: string;
onPress: (event: GestureResponderEvent) => void;
disabled?: boolean;
testID?: string;
variant?: ButtonVariant;
};

export function AppButton({
label,
onPress,
disabled = false,
testID,
variant = 'primary',
}: AppButtonProps) {
return (
<Pressable
accessibilityRole="button"
disabled={disabled}
onPress={onPress}
style={({ pressed }) => [
styles.button,
styles[variant],
pressed && !disabled && styles.pressed,
disabled && styles.disabled,
]}
testID={testID}
>
<Text style={[styles.label, styles[`${variant}Label`]]}>{label}</Text>
</Pressable>
);
}

const styles = StyleSheet.create({
button: {
minHeight: 56,
borderRadius: 999,
alignItems: 'center',
justifyContent: 'center',
paddingHorizontal: spacing.xl,
paddingVertical: spacing.lg,
},
disabled: {
opacity: 0.48,
},
ghost: {
backgroundColor: 'transparent',
},
ghostLabel: {
color: colors.muted,
},
label: {
fontSize: 16,
fontWeight: '700',
},
pressed: {
opacity: 0.82,
},
primary: {
backgroundColor: colors.primary,
},
primaryLabel: {
color: colors.surface,
},
secondary: {
backgroundColor: colors.primarySoft,
borderColor: colors.border,
},
secondaryLabel: {
color: colors.primaryDark,
},
});
57 changes: 57 additions & 0 deletions examples/0.84/src/components/Screen.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import type { PropsWithChildren, ReactNode } from 'react';
import type { StyleProp, ViewStyle } from 'react-native';
import { ScrollView, StyleSheet, View } from 'react-native';

import { colors, spacing } from '../theme';

type ScreenProps = PropsWithChildren<{
contentContainerStyle?: StyleProp<ViewStyle>;
footer?: ReactNode;
scrollEnabled?: boolean;
testID?: string;
}>;

export function Screen({
children,
contentContainerStyle,
footer,
scrollEnabled = true,
testID,
}: ScreenProps) {
return (
<View style={styles.container} testID={testID}>
<ScrollView
contentContainerStyle={[styles.content, contentContainerStyle]}
keyboardShouldPersistTaps="handled"
scrollEnabled={scrollEnabled}
style={styles.scroll}
>
{children}
</ScrollView>
{footer ? <View style={styles.footer}>{footer}</View> : null}
</View>
);
}

const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: colors.background,
},
content: {
flexGrow: 1,
gap: spacing.xl,
paddingHorizontal: spacing.xl,
paddingTop: spacing.xl,
paddingBottom: spacing.xxl,
},
footer: {
backgroundColor: colors.background,
paddingHorizontal: spacing.xl,
paddingTop: spacing.md,
paddingBottom: spacing.xl,
},
scroll: {
flex: 1,
},
});
55 changes: 55 additions & 0 deletions examples/0.84/src/components/Section.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import type { PropsWithChildren, ReactNode } from 'react';
import { StyleSheet, Text, View } from 'react-native';

import { colors, spacing } from '../theme';

type SectionProps = PropsWithChildren<{
action?: ReactNode;
eyebrow?: string;
title: string;
}>;

export function Section({ action, children, eyebrow, title }: SectionProps) {
return (
<View style={styles.section}>
<View style={styles.header}>
<View style={styles.titleGroup}>
{eyebrow ? <Text style={styles.eyebrow}>{eyebrow}</Text> : null}
<Text style={styles.title}>{title}</Text>
</View>
{action}
</View>
<View style={styles.body}>{children}</View>
</View>
);
}

const styles = StyleSheet.create({
body: {
gap: spacing.md,
},
eyebrow: {
color: colors.primaryDark,
fontSize: 12,
fontWeight: '700',
textTransform: 'uppercase',
},
header: {
alignItems: 'flex-start',
flexDirection: 'row',
gap: spacing.md,
justifyContent: 'space-between',
},
section: {
gap: spacing.md,
},
title: {
color: colors.ink,
fontSize: 20,
fontWeight: '800',
},
titleGroup: {
flex: 1,
gap: spacing.xs,
},
});
Loading
Loading