diff --git a/apps/native-component-list/App.tsx b/apps/native-component-list/App.tsx
index 4457575204ed2..41157401779ef 100644
--- a/apps/native-component-list/App.tsx
+++ b/apps/native-component-list/App.tsx
@@ -5,6 +5,8 @@ import { Platform, StatusBar } from 'react-native';
import RootNavigation from './src/navigation/RootNavigation';
import loadAssetsAsync from './src/utilities/loadAssetsAsync';
+SplashScreen.preventAutoHideAsync();
+
function useSplashScreen(loadingFunction: () => void) {
const [isLoadingCompleted, setLoadingComplete] = React.useState(false);
@@ -12,7 +14,6 @@ function useSplashScreen(loadingFunction: () => void) {
React.useEffect(() => {
async function loadAsync() {
try {
- await SplashScreen.preventAutoHideAsync();
await loadingFunction();
} catch (e) {
// We might want to provide this error information to an error reporting service
diff --git a/apps/native-component-list/app.json b/apps/native-component-list/app.json
index d2fde86cdcbd0..3bc77d524b414 100644
--- a/apps/native-component-list/app.json
+++ b/apps/native-component-list/app.json
@@ -30,6 +30,9 @@
"updates": {
"url": "https://u.expo.dev/2c28de10-a2cd-11e6-b8ce-59d1587e6774"
},
+ "web": {
+ "bundler": "metro"
+ },
"facebookScheme": "fb1696089354000816",
"facebookAppId": "1696089354000816",
"facebookDisplayName": "Expo APIs",
diff --git a/apps/native-component-list/index.js b/apps/native-component-list/index.js
index ff8a0d4cf9f81..b975ba3a8a3f7 100644
--- a/apps/native-component-list/index.js
+++ b/apps/native-component-list/index.js
@@ -1,3 +1,4 @@
+import '@expo/metro-runtime';
import { registerRootComponent } from 'expo';
import App from './App';
diff --git a/apps/native-component-list/package.json b/apps/native-component-list/package.json
index 55232e37c0e9d..6d1faa2a8d7cb 100644
--- a/apps/native-component-list/package.json
+++ b/apps/native-component-list/package.json
@@ -6,14 +6,13 @@
"private": true,
"main": "index.js",
"scripts": {
- "build:web": "expo export:web",
- "web": "expo start --web --https",
- "eject": "SDK_VERSION=43.0.0 expo prebuild",
+ "build:web": "expo export -p web",
+ "web": "expo start --web",
"lint": "eslint .",
"tsc": "tsc --noEmit -p ./tsconfig.json",
"start": "expo start",
- "ios": "react-native run-ios",
- "android": "react-native run-android"
+ "ios": "expo run:ios",
+ "android": "expo run:android"
},
"expo": {
"autolinking": {
@@ -153,7 +152,6 @@
},
"devDependencies": {
"@babel/core": "^7.23.7",
- "@babel/plugin-transform-export-namespace-from": "^7.23.4",
"@types/fbemitter": "^2.0.32",
"@types/i18n-js": "^3.0.1",
"@types/pixi.js": "^4.8.6",
@@ -161,7 +159,6 @@
"@types/three": "^0.137.0",
"@types/victory": "^31.0.14",
"babel-jest": "^29.2.1",
- "babel-preset-expo": "~10.0.0",
"expo-module-scripts": "^3.0.0",
"jest": "^29.2.1",
"react-test-renderer": "18.2.0"
diff --git a/apps/native-component-list/src/components/HeaderIconButton.tsx b/apps/native-component-list/src/components/HeaderIconButton.tsx
index 46eac6e013294..aed380c3e3a73 100644
--- a/apps/native-component-list/src/components/HeaderIconButton.tsx
+++ b/apps/native-component-list/src/components/HeaderIconButton.tsx
@@ -1,5 +1,4 @@
-import Ionicons from '@expo/vector-icons/build/Ionicons';
-import React from 'react';
+import Ionicons from '@expo/vector-icons/Ionicons';
import { StyleSheet, TouchableOpacity, TouchableOpacityProps } from 'react-native';
type Props = TouchableOpacityProps & {
diff --git a/apps/native-component-list/src/components/SearchBar.ios.tsx b/apps/native-component-list/src/components/SearchBar.ios.tsx
index c1736436857ba..7abc04e7870d8 100644
--- a/apps/native-component-list/src/components/SearchBar.ios.tsx
+++ b/apps/native-component-list/src/components/SearchBar.ios.tsx
@@ -1,4 +1,4 @@
-import Ionicons from '@expo/vector-icons/build/Ionicons';
+import Ionicons from '@expo/vector-icons/Ionicons';
import { useNavigation } from '@react-navigation/native';
import React from 'react';
import {
diff --git a/apps/native-component-list/src/components/SearchBar.tsx b/apps/native-component-list/src/components/SearchBar.tsx
index 9b3af6c68fa75..ee830d1c10df6 100644
--- a/apps/native-component-list/src/components/SearchBar.tsx
+++ b/apps/native-component-list/src/components/SearchBar.tsx
@@ -1,4 +1,4 @@
-import Ionicons from '@expo/vector-icons/build/Ionicons';
+import Ionicons from '@expo/vector-icons/Ionicons';
import React from 'react';
import { StyleSheet, TextInput, TextStyle, TouchableOpacity, View, Platform } from 'react-native';
diff --git a/apps/native-component-list/src/components/ShowActionSheetButton.tsx b/apps/native-component-list/src/components/ShowActionSheetButton.tsx
index 39415d26ff673..cc51597f2ab5e 100644
--- a/apps/native-component-list/src/components/ShowActionSheetButton.tsx
+++ b/apps/native-component-list/src/components/ShowActionSheetButton.tsx
@@ -1,45 +1,33 @@
import { ActionSheetOptions } from '@expo/react-native-action-sheet';
-import MaterialCommunityIcons from '@expo/vector-icons/build/MaterialCommunityIcons';
-import React from 'react';
+import MaterialCommunityIcons from '@expo/vector-icons/MaterialCommunityIcons';
import { Text, TextStyle, View } from 'react-native';
const icon = (name: string) => ;
-interface Props {
+// A custom button that shows examples of different share sheet configurations
+export default function ShowActionSheetButton({
+ title,
+ withTitle = false,
+ withMessage = false,
+ withIcons = false,
+ withSeparators = false,
+ withCustomStyles = false,
+ onSelection = null,
+ showActionSheetWithOptions,
+}: {
title: string;
showActionSheetWithOptions: (
options: ActionSheetOptions,
onSelection: (index: number) => void
) => void;
- onSelection: (index: number) => void;
+ onSelection: ((index: number) => void) | null;
withTitle?: boolean;
withMessage?: boolean;
withIcons?: boolean;
withSeparators?: boolean;
withCustomStyles?: boolean;
-}
-
-// A custom button that shows examples of different share sheet configurations
-export default class ShowActionSheetButton extends React.PureComponent {
- static defaultProps = {
- withTitle: false,
- withMessage: false,
- withIcons: false,
- withSeparators: false,
- withCustomStyles: false,
- onSelection: null,
- };
-
- _showActionSheet = () => {
- const {
- withTitle,
- withMessage,
- withIcons,
- withSeparators,
- withCustomStyles,
- onSelection,
- showActionSheetWithOptions,
- } = this.props;
+}) {
+ const showActionSheet = () => {
// Same interface as https://facebook.github.io/react-native/docs/actionsheetios.html
const options = ['Delete', 'Save', 'Share', 'Cancel'];
const icons = withIcons
@@ -82,28 +70,25 @@ export default class ShowActionSheetButton extends React.PureComponent {
},
(buttonIndex) => {
// Do something here depending on the button index selected
- onSelection(buttonIndex);
+ onSelection?.(buttonIndex);
}
);
};
- render() {
- const { title } = this.props;
- return (
-
-
-
- {title}
-
-
-
- );
- }
+ return (
+
+
+
+ {title}
+
+
+
+ );
}
diff --git a/apps/native-component-list/src/components/TabIcon.tsx b/apps/native-component-list/src/components/TabIcon.tsx
index ec24280a32cce..ce9cbc115a51b 100644
--- a/apps/native-component-list/src/components/TabIcon.tsx
+++ b/apps/native-component-list/src/components/TabIcon.tsx
@@ -1,4 +1,4 @@
-import MaterialCommunityIcons from '@expo/vector-icons/build/MaterialCommunityIcons';
+import MaterialCommunityIcons from '@expo/vector-icons/MaterialCommunityIcons';
import React from 'react';
import { Platform } from 'react-native';
diff --git a/apps/native-component-list/src/navigation/StackConfig.tsx b/apps/native-component-list/src/navigation/StackConfig.tsx
index 3dd4f3eeabc21..529c0114b404a 100644
--- a/apps/native-component-list/src/navigation/StackConfig.tsx
+++ b/apps/native-component-list/src/navigation/StackConfig.tsx
@@ -1,4 +1,4 @@
-import Ionicons from '@expo/vector-icons/build/Ionicons';
+import Ionicons from '@expo/vector-icons/Ionicons';
import { BottomTabNavigationProp } from '@react-navigation/bottom-tabs';
import { HeaderStyleInterpolators } from '@react-navigation/stack';
import * as React from 'react';
diff --git a/apps/native-component-list/src/screens/AV/Player.tsx b/apps/native-component-list/src/screens/AV/Player.tsx
index 5daf849faf449..8ee20c2f1d3d2 100644
--- a/apps/native-component-list/src/screens/AV/Player.tsx
+++ b/apps/native-component-list/src/screens/AV/Player.tsx
@@ -1,4 +1,4 @@
-import Ionicons from '@expo/vector-icons/build/Ionicons';
+import Ionicons from '@expo/vector-icons/Ionicons';
import Slider from '@react-native-community/slider';
import SegmentedControl from '@react-native-segmented-control/segmented-control';
import { AVMetadata } from 'expo-av';
diff --git a/apps/native-component-list/src/screens/AV/Recorder.tsx b/apps/native-component-list/src/screens/AV/Recorder.tsx
index bd1642548eca0..317fef630e923 100644
--- a/apps/native-component-list/src/screens/AV/Recorder.tsx
+++ b/apps/native-component-list/src/screens/AV/Recorder.tsx
@@ -1,4 +1,4 @@
-import Ionicons from '@expo/vector-icons/build/Ionicons';
+import Ionicons from '@expo/vector-icons/Ionicons';
import { Audio } from 'expo-av';
import React from 'react';
import {
diff --git a/apps/native-component-list/src/screens/AV/RecordingScreen.tsx b/apps/native-component-list/src/screens/AV/RecordingScreen.tsx
index 77815a3d66773..9a8a4df6aed3c 100644
--- a/apps/native-component-list/src/screens/AV/RecordingScreen.tsx
+++ b/apps/native-component-list/src/screens/AV/RecordingScreen.tsx
@@ -1,46 +1,33 @@
-import React from 'react';
-import { PixelRatio, ScrollView, StyleSheet } from 'react-native';
+import { useState } from 'react';
+import { ScrollView, StyleSheet } from 'react-native';
import AudioModeSelector from './AudioModeSelector';
import Player from './AudioPlayer';
import Recorder from './Recorder';
import HeadingText from '../../components/HeadingText';
-interface State {
- recordingUri?: string;
+export default function RecordingScreen() {
+ const [recordingUri, setRecordingUri] = useState(undefined);
+
+ return (
+
+ Audio mode
+
+ Recorder
+ setRecordingUri(recordingUri)} />
+ {recordingUri && (
+ <>
+ Last recording
+
+ >
+ )}
+
+ );
}
-// See: https://github.com/expo/expo/pull/10229#discussion_r490961694
-// eslint-disable-next-line @typescript-eslint/ban-types
-export default class RecordingScreen extends React.Component<{}, State> {
- static navigationOptions = {
- title: 'Audio Recording',
- };
-
- readonly state: State = {};
-
- _handleRecordingFinished = (recordingUri: string) => this.setState({ recordingUri });
-
- _maybeRenderLastRecording = () =>
- this.state.recordingUri ? (
- <>
- Last recording
-
- >
- ) : null;
-
- render() {
- return (
-
- Audio mode
-
- Recorder
-
- {this._maybeRenderLastRecording()}
-
- );
- }
-}
+RecordingScreen.navigationOptions = {
+ title: 'Audio Recording',
+};
const styles = StyleSheet.create({
contentContainer: {
@@ -65,7 +52,7 @@ const styles = StyleSheet.create({
marginHorizontal: 30,
},
player: {
- borderBottomWidth: 1.0 / PixelRatio.get(),
+ borderBottomWidth: StyleSheet.hairlineWidth,
borderBottomColor: '#cccccc',
},
});
diff --git a/apps/native-component-list/src/screens/AppearanceScreen.tsx b/apps/native-component-list/src/screens/AppearanceScreen.tsx
index 9719a5de8b006..c2a983f40a4e6 100644
--- a/apps/native-component-list/src/screens/AppearanceScreen.tsx
+++ b/apps/native-component-list/src/screens/AppearanceScreen.tsx
@@ -1,54 +1,25 @@
-import React from 'react';
-import { Appearance, StyleSheet, Text, View } from 'react-native';
-import type { NativeEventSubscription } from 'react-native';
+import { StyleSheet, Text, View, useColorScheme } from 'react-native';
-type ColorSchemeName = Appearance.AppearancePreferences['colorScheme'];
+export default function AppearanceScreen() {
+ const colorScheme = useColorScheme();
-interface State {
- colorScheme: ColorSchemeName;
-}
-
-// See: https://github.com/expo/expo/pull/10229#discussion_r490961694
-// eslint-disable-next-line @typescript-eslint/ban-types
-export default class AppearanceScreen extends React.Component<{}, State> {
- static navigationOptions = {
- title: 'Appearance',
- };
-
- subscription?: NativeEventSubscription;
-
- state: State = {
- colorScheme: Appearance.getColorScheme(),
- };
+ const isDark = colorScheme === 'dark';
- componentDidMount() {
- this.subscription = Appearance.addChangeListener(
- ({ colorScheme }: { colorScheme: ColorSchemeName }) => {
- this.setState({ colorScheme });
- }
- );
- }
+ return (
+
+
+ {`Current color scheme: `}
- componentWillUnmount() {
- if (this.subscription) this.subscription.remove();
- }
-
- render() {
- const { colorScheme } = this.state;
- const isDark = colorScheme === 'dark';
-
- return (
-
-
- {`Current color scheme: `}
-
- {this.state.colorScheme}
-
-
- );
- }
+ {colorScheme}
+
+
+ );
}
+AppearanceScreen.navigationOptions = {
+ title: 'Appearance',
+};
+
const styles = StyleSheet.create({
screen: {
flex: 1,
diff --git a/apps/native-component-list/src/screens/CalendarsScreen.tsx b/apps/native-component-list/src/screens/CalendarsScreen.tsx
index 0651a34bff475..ffd05d6788ef5 100644
--- a/apps/native-component-list/src/screens/CalendarsScreen.tsx
+++ b/apps/native-component-list/src/screens/CalendarsScreen.tsx
@@ -1,6 +1,6 @@
-import { StackNavigationProp } from '@react-navigation/stack';
+import type { StackNavigationProp } from '@react-navigation/stack';
import * as Calendar from 'expo-calendar';
-import React from 'react';
+import { useState } from 'react';
import { Alert, Platform, ScrollView, StyleSheet, View } from 'react-native';
import Button from '../components/Button';
@@ -44,76 +44,33 @@ const CalendarRow = (props: {
);
};
-CalendarRow.navigationOptions = {
- title: 'Calendars',
-};
-
-interface State {
- haveCalendarPermissions: boolean;
- haveReminderPermissions: boolean;
- calendars: Calendar.Calendar[];
- activeCalendarId?: string;
- activeCalendarEvents: Calendar.Event[];
- showAddNewEventForm: boolean;
- editingEvent?: Calendar.Event;
-}
-
-export default class CalendarsScreen extends React.Component<
- { navigation: StackNavigation },
- State
-> {
- static navigationOptions = {
- title: 'Calendars',
- };
-
- readonly state: State = {
- haveCalendarPermissions: false,
- haveReminderPermissions: false,
- calendars: [],
- activeCalendarEvents: [],
- showAddNewEventForm: false,
- };
- _askForCalendarPermissions = async () => {
- const response = await Calendar.requestCalendarPermissionsAsync();
- const granted = response.status === 'granted';
- this.setState({
- haveCalendarPermissions: granted,
- });
- return granted;
- };
+export default function CalendarsScreen({ navigation }: { navigation: StackNavigation }) {
+ const [, askForCalendarPermissions] = Calendar.useCalendarPermissions();
+ const [, askForReminderPermissions] = Calendar.useRemindersPermissions();
- _askForReminderPermissions = async () => {
- if (Platform.OS === 'android') return true;
- const response = await Calendar.requestRemindersPermissionsAsync();
- const granted = response.status === 'granted';
- this.setState({
- haveReminderPermissions: granted,
- });
- return granted;
- };
+ const [calendars, setCalendars] = useState([]);
- _findCalendars = async () => {
- const calendarGranted = await this._askForCalendarPermissions();
- const reminderGranted = await this._askForReminderPermissions();
+ const findCalendars = async () => {
+ const calendarGranted = (await askForCalendarPermissions()).granted;
+ const reminderGranted = (await askForReminderPermissions()).granted;
if (calendarGranted && reminderGranted) {
const eventCalendars = (await Calendar.getCalendarsAsync('event')) as unknown as any[];
const reminderCalendars = (
Platform.OS === 'ios' ? await Calendar.getCalendarsAsync('reminder') : []
) as any[];
- this.setState({ calendars: [...eventCalendars, ...reminderCalendars] });
+ setCalendars([...eventCalendars, ...reminderCalendars]);
}
};
- _addCalendar = async () => {
+ const addCalendar = async () => {
const sourceDetails = Platform.select({
default: () => ({}),
ios: () => ({
- sourceId: this.state.calendars.find((cal) => cal.source && cal.source.name === 'Default')
- ?.source.id,
+ sourceId: calendars.find((cal) => cal.source && cal.source.name === 'Default')?.source.id,
}),
android: () => {
- const calendar = this.state.calendars.find(
+ const calendar = calendars.find(
(cal) => cal.accessLevel === Calendar.CalendarAccessLevel.OWNER
);
return calendar ? { source: calendar.source, ownerAccount: calendar.ownerAccount } : {};
@@ -130,26 +87,26 @@ export default class CalendarsScreen extends React.Component<
try {
await Calendar.createCalendarAsync(newCalendar);
Alert.alert('Calendar saved successfully');
- this._findCalendars();
+ findCalendars();
} catch (e) {
Alert.alert('Calendar not saved successfully', e.message);
}
};
- _updateCalendar = async (calendarId: string) => {
+ const updateCalendar = async (calendarId: string) => {
const newCalendar = {
title: 'cool updated calendar',
};
try {
await Calendar.updateCalendarAsync(calendarId, newCalendar);
Alert.alert('Calendar saved successfully');
- this._findCalendars();
+ findCalendars();
} catch (e) {
Alert.alert('Calendar not saved successfully', e.message);
}
};
- _deleteCalendar = async (calendar: any) => {
+ const deleteCalendar = async (calendar: any) => {
Alert.alert(`Are you sure you want to delete ${calendar.title}?`, 'This cannot be undone.', [
{
text: 'Cancel',
@@ -157,11 +114,11 @@ export default class CalendarsScreen extends React.Component<
},
{
text: 'OK',
- onPress: async () => {
+ async onPress() {
try {
await Calendar.deleteCalendarAsync(calendar.id);
Alert.alert('Calendar deleted successfully');
- this._findCalendars();
+ findCalendars();
} catch (e) {
Alert.alert('Calendar not deleted successfully', e.message);
}
@@ -170,32 +127,38 @@ export default class CalendarsScreen extends React.Component<
]);
};
- render() {
- if (this.state.calendars.length) {
- return (
-
-
- {this.state.calendars.map((calendar) => (
-
- ))}
-
- );
- }
-
+ if (calendars.length) {
return (
-
-
-
+
+
+ {calendars.map((calendar) => (
+
+ ))}
+
);
}
+
+ return (
+
+
+
+ );
}
+CalendarRow.navigationOptions = {
+ title: 'Calendars',
+};
+
+CalendarsScreen.navigationOptions = {
+ title: 'Calendars',
+};
+
const styles = StyleSheet.create({
container: {
backgroundColor: Colors.greyBackground,
diff --git a/apps/native-component-list/src/screens/Camera/CameraScreen.tsx b/apps/native-component-list/src/screens/Camera/CameraScreen.tsx
index 4426eddf8371b..35936dabb1757 100644
--- a/apps/native-component-list/src/screens/Camera/CameraScreen.tsx
+++ b/apps/native-component-list/src/screens/Camera/CameraScreen.tsx
@@ -1,5 +1,5 @@
-import Ionicons from '@expo/vector-icons/build/Ionicons';
-import MaterialCommunityIcons from '@expo/vector-icons/build/MaterialCommunityIcons';
+import Ionicons from '@expo/vector-icons/Ionicons';
+import MaterialCommunityIcons from '@expo/vector-icons/MaterialCommunityIcons';
import { BarCodeScanner } from 'expo-barcode-scanner';
import {
AutoFocus,
diff --git a/apps/native-component-list/src/screens/Camera/CameraScreenNext.tsx b/apps/native-component-list/src/screens/Camera/CameraScreenNext.tsx
index 2c9fe4409afd3..d25f87860a1c1 100644
--- a/apps/native-component-list/src/screens/Camera/CameraScreenNext.tsx
+++ b/apps/native-component-list/src/screens/Camera/CameraScreenNext.tsx
@@ -1,5 +1,5 @@
-import Ionicons from '@expo/vector-icons/build/Ionicons';
-import MaterialCommunityIcons from '@expo/vector-icons/build/MaterialCommunityIcons';
+import Ionicons from '@expo/vector-icons/Ionicons';
+import MaterialCommunityIcons from '@expo/vector-icons/MaterialCommunityIcons';
import {
BarcodePoint,
BarcodeScanningResult,
diff --git a/apps/native-component-list/src/screens/Camera/GalleryScreen.tsx b/apps/native-component-list/src/screens/Camera/GalleryScreen.tsx
index 7fff6503b923a..fd328fd2d5f85 100644
--- a/apps/native-component-list/src/screens/Camera/GalleryScreen.tsx
+++ b/apps/native-component-list/src/screens/Camera/GalleryScreen.tsx
@@ -1,4 +1,4 @@
-import MaterialIcons from '@expo/vector-icons/build/MaterialIcons';
+import MaterialIcons from '@expo/vector-icons/MaterialIcons';
import * as FileSystem from 'expo-file-system';
import * as MediaLibrary from 'expo-media-library';
import React from 'react';
diff --git a/apps/native-component-list/src/screens/Camera/Photo.tsx b/apps/native-component-list/src/screens/Camera/Photo.tsx
index cc56f050d9df3..604d705718e98 100644
--- a/apps/native-component-list/src/screens/Camera/Photo.tsx
+++ b/apps/native-component-list/src/screens/Camera/Photo.tsx
@@ -1,4 +1,4 @@
-import Ionicons from '@expo/vector-icons/build/Ionicons';
+import Ionicons from '@expo/vector-icons/Ionicons';
import * as VideoThumbnails from 'expo-video-thumbnails';
import React from 'react';
import { Image, StyleSheet, TouchableOpacity } from 'react-native';
diff --git a/apps/native-component-list/src/screens/Camera/Photo.web.tsx b/apps/native-component-list/src/screens/Camera/Photo.web.tsx
index d9d80b60720cb..7f0f938c1b490 100644
--- a/apps/native-component-list/src/screens/Camera/Photo.web.tsx
+++ b/apps/native-component-list/src/screens/Camera/Photo.web.tsx
@@ -1,4 +1,4 @@
-import Ionicons from '@expo/vector-icons/build/Ionicons';
+import Ionicons from '@expo/vector-icons/Ionicons';
import React from 'react';
import { Image, StyleSheet, TouchableOpacity } from 'react-native';
diff --git a/apps/native-component-list/src/screens/ComponentListScreen.tsx b/apps/native-component-list/src/screens/ComponentListScreen.tsx
index de5056a8fe2d0..8ff047a0f1808 100644
--- a/apps/native-component-list/src/screens/ComponentListScreen.tsx
+++ b/apps/native-component-list/src/screens/ComponentListScreen.tsx
@@ -1,4 +1,4 @@
-import Ionicons from '@expo/vector-icons/build/Ionicons';
+import Ionicons from '@expo/vector-icons/Ionicons';
import { Link, useLinkProps } from '@react-navigation/native';
import React from 'react';
import {
diff --git a/apps/native-component-list/src/screens/ConstantsScreen.tsx b/apps/native-component-list/src/screens/ConstantsScreen.tsx
index f977506932b8e..44db38813ff50 100644
--- a/apps/native-component-list/src/screens/ConstantsScreen.tsx
+++ b/apps/native-component-list/src/screens/ConstantsScreen.tsx
@@ -1,80 +1,57 @@
import Constants from 'expo-constants';
-import React from 'react';
+import React, { useEffect } from 'react';
import { ScrollView, View } from 'react-native';
import HeadingText from '../components/HeadingText';
import MonoText from '../components/MonoText';
import Colors from '../constants/Colors';
-interface State {
- value?: string | (() => void);
- error?: Error;
-}
-
-class ExpoConstant extends React.Component<{ value?: any; name: string }, State> {
- readonly state: State = {};
-
- componentDidMount() {
- this.updateValue();
- }
-
- async updateValue() {
- let value = this.props.value;
-
- if (!value) {
- value = Constants[this.props.name];
- }
- if (typeof value === 'function') {
- try {
- value = await this.props.value();
- } catch (error) {
- console.error(error);
- this.setState({ error: error.message });
+function ExpoConstant({ name }: { name: string }) {
+ const [evaluated, setEvaluated] = React.useState(null);
+ const [error, setError] = React.useState(null);
+ useEffect(() => {
+ let value = Constants[name];
+ (async () => {
+ if (typeof value === 'function') {
+ try {
+ value = await value();
+ } catch (error) {
+ console.error(error);
+ return setError(error.message);
+ }
}
- }
- if (typeof value === 'object') {
- value = JSON.stringify(value, null, 2);
- } else if (typeof value === 'boolean') {
- value = value ? 'true' : 'false';
- }
- this.setState({ value });
- }
-
- render() {
- const { value, error } = this.state;
- const { name } = this.props;
- if (!value || typeof value === 'function') {
- return null;
- }
-
- return (
-
- {name}
-
- {error?.message ?? value}
-
-
- );
- }
+ if (typeof value === 'object') {
+ value = JSON.stringify(value, null, 2);
+ } else if (typeof value === 'boolean') {
+ value = value ? 'true' : 'false';
+ }
+ setEvaluated(value);
+ })();
+ }, [name]);
+
+ return (
+
+ {name}
+ {error ?? evaluated}
+
+ );
}
// Ignore deprecated properties
const IGNORED_CONSTANTS = ['__unsafeNoWarnManifest', 'linkingUrl'];
-export default class ConstantsScreen extends React.PureComponent {
- render() {
- return (
-
- {Object.keys(Constants)
- .filter((value) => !IGNORED_CONSTANTS.includes(value))
- .sort()
- .map((key) => {
- if (typeof Constants[key] === 'function') return null;
- return ;
- })}
- Constants.getWebViewUserAgentAsync()} />
-
- );
- }
+export default function ConstantsScreen() {
+ return (
+
+ {Object.keys(Constants)
+ .filter((value) => !IGNORED_CONSTANTS.includes(value))
+ .sort()
+ .map((key) => {
+ if (typeof Constants[key] === 'function') return null;
+ return ;
+ })}
+
+
+ );
}
diff --git a/apps/native-component-list/src/screens/Contacts/ContactDetailList.tsx b/apps/native-component-list/src/screens/Contacts/ContactDetailList.tsx
index 773a309527d73..d170647661533 100644
--- a/apps/native-component-list/src/screens/Contacts/ContactDetailList.tsx
+++ b/apps/native-component-list/src/screens/Contacts/ContactDetailList.tsx
@@ -1,4 +1,4 @@
-import Ionicons from '@expo/vector-icons/build/Ionicons';
+import Ionicons from '@expo/vector-icons/Ionicons';
import * as React from 'react';
import {
SectionList,
diff --git a/apps/native-component-list/src/screens/Contacts/ContactDetailScreen.tsx b/apps/native-component-list/src/screens/Contacts/ContactDetailScreen.tsx
index c014caf88a7b4..6ea60200d8b2a 100644
--- a/apps/native-component-list/src/screens/Contacts/ContactDetailScreen.tsx
+++ b/apps/native-component-list/src/screens/Contacts/ContactDetailScreen.tsx
@@ -1,4 +1,4 @@
-import Ionicons from '@expo/vector-icons/build/Ionicons';
+import Ionicons from '@expo/vector-icons/Ionicons';
import * as Contacts from 'expo-contacts';
import * as ImagePicker from 'expo-image-picker';
import * as Linking from 'expo-linking';
diff --git a/apps/native-component-list/src/screens/Contacts/ContactsListItem.tsx b/apps/native-component-list/src/screens/Contacts/ContactsListItem.tsx
index 4ebcb6c31666d..87f506dffbfd6 100644
--- a/apps/native-component-list/src/screens/Contacts/ContactsListItem.tsx
+++ b/apps/native-component-list/src/screens/Contacts/ContactsListItem.tsx
@@ -1,4 +1,4 @@
-import Ionicons from '@expo/vector-icons/build/Ionicons';
+import Ionicons from '@expo/vector-icons/Ionicons';
import * as React from 'react';
import { StyleSheet, Text, TouchableHighlight, View } from 'react-native';
diff --git a/apps/native-component-list/src/screens/CryptoScreen.tsx b/apps/native-component-list/src/screens/CryptoScreen.tsx
index dea39db8ca9cc..5563795e78837 100644
--- a/apps/native-component-list/src/screens/CryptoScreen.tsx
+++ b/apps/native-component-list/src/screens/CryptoScreen.tsx
@@ -1,6 +1,5 @@
import * as Crypto from 'expo-crypto';
import { CryptoDigestAlgorithm, CryptoEncoding } from 'expo-crypto';
-import React from 'react';
import { ScrollView, StyleSheet, Text } from 'react-native';
import FunctionDemo, { FunctionDescription } from '../components/FunctionDemo';
diff --git a/apps/native-component-list/src/screens/DateTimePickerScreen.web.tsx b/apps/native-component-list/src/screens/DateTimePickerScreen.web.tsx
index 5139663b7a059..381719e01cf90 100644
--- a/apps/native-component-list/src/screens/DateTimePickerScreen.web.tsx
+++ b/apps/native-component-list/src/screens/DateTimePickerScreen.web.tsx
@@ -1,4 +1 @@
-import * as React from 'react';
-import { Text } from 'react-native';
-
-export default () => Date Time Picker is not implemented on web;
+export default () => Date Time Picker is not implemented on web
;
diff --git a/apps/native-component-list/src/screens/ErrorScreen.tsx b/apps/native-component-list/src/screens/ErrorScreen.tsx
index ee6a6c124b54f..e01a9c4dfee2c 100644
--- a/apps/native-component-list/src/screens/ErrorScreen.tsx
+++ b/apps/native-component-list/src/screens/ErrorScreen.tsx
@@ -1,4 +1,3 @@
-import * as React from 'react';
import { Button } from 'react-native';
import { Page, Section } from '../components/Page';
diff --git a/apps/native-component-list/src/screens/ExpoApisScreen.tsx b/apps/native-component-list/src/screens/ExpoApisScreen.tsx
index 95f354bf03372..33fdc45a94000 100644
--- a/apps/native-component-list/src/screens/ExpoApisScreen.tsx
+++ b/apps/native-component-list/src/screens/ExpoApisScreen.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { Platform } from 'react-native';
import ComponentListScreen from './ComponentListScreen';
@@ -96,12 +95,12 @@ export const ScreenItems = screens.map((name) => ({
}));
export default function ExpoApisScreen() {
- const renderItemRight = React.useCallback(
- ({ name }: { name: string }) => (
-
- ),
- []
+ return (
+ (
+
+ )}
+ apis={ScreenItems}
+ />
);
-
- return ;
}
diff --git a/apps/native-component-list/src/screens/ExpoComponentsScreen.tsx b/apps/native-component-list/src/screens/ExpoComponentsScreen.tsx
index 8ce794291044a..de5656145f473 100644
--- a/apps/native-component-list/src/screens/ExpoComponentsScreen.tsx
+++ b/apps/native-component-list/src/screens/ExpoComponentsScreen.tsx
@@ -1,5 +1,3 @@
-import * as React from 'react';
-
import ComponentListScreen from './ComponentListScreen';
import ExpoAPIIcon from '../components/ExpoAPIIcon';
@@ -59,12 +57,12 @@ export const ScreenItems = screens.map((name) => ({
}));
export default function ExpoComponentsScreen() {
- const renderItemRight = React.useCallback(
- ({ name }: { name: string }) => (
-
- ),
- []
+ return (
+ (
+
+ )}
+ apis={ScreenItems}
+ />
);
-
- return ;
}
diff --git a/apps/native-component-list/src/screens/ExpoModulesScreen.tsx b/apps/native-component-list/src/screens/ExpoModulesScreen.tsx
index 17faadfd15611..0232754e31fe5 100644
--- a/apps/native-component-list/src/screens/ExpoModulesScreen.tsx
+++ b/apps/native-component-list/src/screens/ExpoModulesScreen.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { ScrollView, StyleSheet, View } from 'react-native';
import HeadingText from '../components/HeadingText';
@@ -9,32 +8,30 @@ const customJsonReplacer = (_: string, value: any) => {
return typeof value === 'function' ? value.toString().replace(/\s+/g, ' ') : value;
};
-export default class ExpoModulesScreen extends React.PureComponent {
- render() {
- const modules = { ...globalThis.expo?.modules };
- const moduleNames = Object.keys(modules);
+export default function ExpoModulesScreen() {
+ const modules = { ...globalThis.expo?.modules };
+ const moduleNames = Object.keys(modules);
- return (
-
- Host object is installed
- {`'modules' in globalThis.expo => ${'modules' in globalThis.expo!}`}
+ return (
+
+ Host object is installed
+ {`'modules' in globalThis.expo => ${'modules' in globalThis.expo!}`}
- Available Expo modules
-
- {`Object.keys(global.expo.modules) => [\n ${moduleNames.join(',\n ')}\n]`}
-
+ Available Expo modules
+
+ {`Object.keys(global.expo.modules) => [\n ${moduleNames.join(',\n ')}\n]`}
+
- {moduleNames.map((moduleName) => {
- return (
-
- Module: {moduleName}
- {JSON.stringify(modules[moduleName], customJsonReplacer, 2)}
-
- );
- })}
-
- );
- }
+ {moduleNames.map((moduleName) => {
+ return (
+
+ Module: {moduleName}
+ {JSON.stringify(modules[moduleName], customJsonReplacer, 2)}
+
+ );
+ })}
+
+ );
}
const styles = StyleSheet.create({
diff --git a/apps/native-component-list/src/screens/FontScreen.tsx b/apps/native-component-list/src/screens/FontScreen.tsx
index 9487b5054aebd..c68f4d89eaea7 100644
--- a/apps/native-component-list/src/screens/FontScreen.tsx
+++ b/apps/native-component-list/src/screens/FontScreen.tsx
@@ -1,62 +1,59 @@
-import Ionicons from '@expo/vector-icons/build/Ionicons';
-import React from 'react';
+import Ionicons from '@expo/vector-icons/Ionicons';
import { Platform, ScrollView, Text, View } from 'react-native';
-export default class FontScreen extends React.Component {
- static navigationOptions = {
- title: 'Font',
- };
+export default function FontScreen() {
+ return (
+
+
+
+
+
+
+
+
+
- render() {
- return (
-
-
-
-
-
-
-
-
-
-
-
-
- Font icons sets and other custom fonts can be loaded from the web
+
+
+ Font icons sets and other custom fonts can be loaded from the web
+
+
+ Font icons sets and other custom fonts can be loaded by providing remote uri as well.
+
+ {Platform.OS === 'ios' && (
+
+ Custom font with `adjustsFontSizeToFit` on iOS
-
- Font icons sets and other custom fonts can be loaded by providing remote uri as well.
+ )}
+ {Platform.OS === 'ios' && (
+
+ Custom remote uri font with `adjustsFontSizeToFit` on iOS
- {Platform.OS === 'ios' && (
-
- Custom font with `adjustsFontSizeToFit` on iOS
-
- )}
- {Platform.OS === 'ios' && (
-
- Custom remote uri font with `adjustsFontSizeToFit` on iOS
-
- )}
-
-
- );
- }
+ )}
+
+
+ );
}
+
+FontScreen.navigationOptions = {
+ title: 'Font',
+};
diff --git a/apps/native-component-list/src/screens/GL/GLMaskScreen.tsx b/apps/native-component-list/src/screens/GL/GLMaskScreen.tsx
index bab046a347703..285b28666ee31 100644
--- a/apps/native-component-list/src/screens/GL/GLMaskScreen.tsx
+++ b/apps/native-component-list/src/screens/GL/GLMaskScreen.tsx
@@ -1,6 +1,6 @@
import MaskedView from '@react-native-masked-view/masked-view';
import * as GL from 'expo-gl';
-import React from 'react';
+import { useCallback } from 'react';
import { Text, View } from 'react-native';
const vertSrc = `
@@ -18,104 +18,100 @@ void main () {
gl_FragColor = vec4(uv.x, uv.y, 0.5, 1.0);
}`;
-interface Props {
- speed?: number;
-}
-
-export default class GLMaskScreen extends React.Component {
- static title = 'MaskedView integration';
-
- static navigationOptions = {
- title: 'Mask GLView Example',
- };
-
- render() {
- return (
-
-
- GL IS COOL
-
-
- }>
-
-
- );
- }
+export default function GLMaskScreen(props: { speed?: number }) {
+ const _onContextCreate = useCallback(
+ (gl: GL.ExpoWebGLRenderingContext) => {
+ // Compile vertex and fragment shader
+ const vert = gl.createShader(gl.VERTEX_SHADER)!;
+ gl.shaderSource(vert, vertSrc);
+ gl.compileShader(vert);
+ const frag = gl.createShader(gl.FRAGMENT_SHADER)!;
+ gl.shaderSource(frag, fragSrc);
+ gl.compileShader(frag);
- _onContextCreate = (gl: GL.ExpoWebGLRenderingContext) => {
- // Compile vertex and fragment shader
- const vert = gl.createShader(gl.VERTEX_SHADER)!;
- gl.shaderSource(vert, vertSrc);
- gl.compileShader(vert);
- const frag = gl.createShader(gl.FRAGMENT_SHADER)!;
- gl.shaderSource(frag, fragSrc);
- gl.compileShader(frag);
+ // Link together into a program
+ const program = gl.createProgram()!;
+ gl.attachShader(program, vert);
+ gl.attachShader(program, frag);
+ gl.linkProgram(program);
- // Link together into a program
- const program = gl.createProgram()!;
- gl.attachShader(program, vert);
- gl.attachShader(program, frag);
- gl.linkProgram(program);
+ // Save position attribute
+ const positionAttrib = gl.getAttribLocation(program, 'position');
- // Save position attribute
- const positionAttrib = gl.getAttribLocation(program, 'position');
+ // Create buffer
+ const buffer = gl.createBuffer();
- // Create buffer
- const buffer = gl.createBuffer();
+ // Animate!
+ let skip = false;
+ const animate = () => {
+ try {
+ if (skip) {
+ // return;
+ }
- // Animate!
- let skip = false;
- const animate = () => {
- try {
- if (skip) {
- // return;
- }
+ // Clear
+ gl.clearColor(0, 0, 1, 1);
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
- // Clear
- gl.clearColor(0, 0, 1, 1);
- gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+ // Bind buffer, program and position attribute for use
+ gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
+ gl.useProgram(program);
+ gl.enableVertexAttribArray(positionAttrib);
+ gl.vertexAttribPointer(positionAttrib, 2, gl.FLOAT, false, 0, 0);
- // Bind buffer, program and position attribute for use
- gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
- gl.useProgram(program);
- gl.enableVertexAttribArray(positionAttrib);
- gl.vertexAttribPointer(positionAttrib, 2, gl.FLOAT, false, 0, 0);
-
- // Buffer data and draw!
- const speed = this.props.speed || 1;
- const a = 0.48 * Math.sin(0.001 * speed * Date.now()) + 0.5;
- // prettier-ignore
- const verts = new Float32Array([
+ // Buffer data and draw!
+ const speed = props.speed || 1;
+ const a = 0.48 * Math.sin(0.001 * speed * Date.now()) + 0.5;
+ // prettier-ignore
+ const verts = new Float32Array([
-a, -a, a, -a,
-a, a, -a, a,
a, -a, a, a,
]);
- gl.bufferData(gl.ARRAY_BUFFER, verts, gl.STATIC_DRAW);
- gl.drawArrays(gl.TRIANGLES, 0, verts.length / 2);
+ gl.bufferData(gl.ARRAY_BUFFER, verts, gl.STATIC_DRAW);
+ gl.drawArrays(gl.TRIANGLES, 0, verts.length / 2);
+
+ // Submit frame
+ gl.flush();
+ gl.endFrameEXP();
+ } finally {
+ skip = !skip;
+ requestAnimationFrame(animate);
+ }
+ };
+ animate();
+ },
+ [props.speed]
+ );
- // Submit frame
- gl.flush();
- gl.endFrameEXP();
- } finally {
- skip = !skip;
- requestAnimationFrame(animate);
- }
- };
- animate();
- };
+ return (
+
+
+ GL IS COOL
+
+
+ }>
+
+
+ );
}
+
+GLMaskScreen.title = 'MaskedView integration';
+GLMaskScreen.navigationOptions = {
+ title: 'Mask GLView Example',
+};
diff --git a/apps/native-component-list/src/screens/GestureHandler/GmailStyleSwipeableRow.tsx b/apps/native-component-list/src/screens/GestureHandler/GmailStyleSwipeableRow.tsx
index 1a9d04a499916..61941a38c134f 100644
--- a/apps/native-component-list/src/screens/GestureHandler/GmailStyleSwipeableRow.tsx
+++ b/apps/native-component-list/src/screens/GestureHandler/GmailStyleSwipeableRow.tsx
@@ -1,5 +1,5 @@
// @ts-nocheck
-import MaterialIcons from '@expo/vector-icons/build/MaterialIcons';
+import MaterialIcons from '@expo/vector-icons/MaterialIcons';
import React, { Component } from 'react';
import { Animated, StyleSheet } from 'react-native';
import { RectButton } from 'react-native-gesture-handler';
diff --git a/apps/native-component-list/src/screens/GestureHandlerListScreen.tsx b/apps/native-component-list/src/screens/GestureHandlerListScreen.tsx
index a4dd142af6fef..fa8e074cec75c 100644
--- a/apps/native-component-list/src/screens/GestureHandlerListScreen.tsx
+++ b/apps/native-component-list/src/screens/GestureHandlerListScreen.tsx
@@ -1,55 +1,52 @@
-import React from 'react';
import { Dimensions, StyleSheet, Text, View } from 'react-native';
import { ScrollView } from 'react-native-gesture-handler';
import BouncyBox from './GestureHandler/BouncyBox';
import FancyButton from './GestureHandler/FancyButton';
-export default class GestureHandlerListScreen extends React.Component {
- static navigationOptions = {
- title: 'Gesture Handler List',
- };
+export default function GestureHandlerListScreen() {
+ return (
+
+ LongPressGestureHandler, TapGestureHandler
+
+ You can single tap, double tap, or long press these buttons!
+
+ alert('Single tap')}
+ onDoubleTap={() => alert('Double tap')}
+ onLongPress={() => alert('Long press')}>
+ Try this button out!
+
- render() {
- return (
-
- LongPressGestureHandler, TapGestureHandler
-
- You can single tap, double tap, or long press these buttons!
-
- alert('Single tap')}
- onDoubleTap={() => alert('Double tap')}
- onLongPress={() => alert('Long press')}>
- Try this button out!
-
+
-
+ alert('Single tap #2!')}
+ onDoubleTap={() => alert('Double tap #2!')}
+ onLongPress={() => alert('Long press #2!')}>
+ A second fancy button!
+
- alert('Single tap #2!')}
- onDoubleTap={() => alert('Double tap #2!')}
- onLongPress={() => alert('Long press #2!')}>
- A second fancy button!
-
+
-
+ PanGestureHandler, RotationGestureHandler
+
+ You can drag it left and right, and also use two fingers to rotate it, and it'll bounce
+ back!
+
- PanGestureHandler, RotationGestureHandler
-
- You can drag it left and right, and also use two fingers to rotate it, and it'll bounce
- back!
-
-
-
-
-
-
-
- );
- }
+
+
+
+
+
+ );
}
+GestureHandlerListScreen.navigationOptions = {
+ title: 'Gesture Handler List',
+};
+
const styles = StyleSheet.create({
container: {
flex: 1,
diff --git a/apps/native-component-list/src/screens/GestureHandlerSwipeableScreen.tsx b/apps/native-component-list/src/screens/GestureHandlerSwipeableScreen.tsx
index fb117692e6f9a..2125bb9034978 100644
--- a/apps/native-component-list/src/screens/GestureHandlerSwipeableScreen.tsx
+++ b/apps/native-component-list/src/screens/GestureHandlerSwipeableScreen.tsx
@@ -1,11 +1,11 @@
-import React, { Component } from 'react';
+import type { FunctionComponent } from 'react';
import { Alert, StyleSheet, Text, View } from 'react-native';
import { FlatList, RectButton } from 'react-native-gesture-handler';
import AppleStyleSwipeableRow from './GestureHandler/AppleStyleSwipeableRow';
import GmailStyleSwipeableRow from './GestureHandler/GmailStyleSwipeableRow';
-const Row: React.FunctionComponent<{ item: Item }> = ({ item }) => (
+const Row: FunctionComponent<{ item: Item }> = ({ item }) => (
Alert.alert(item.from)}>
{item.from}
@@ -15,7 +15,7 @@ const Row: React.FunctionComponent<{ item: Item }> = ({ item }) => (
);
-const SwipeableRow: React.FunctionComponent<{ item: Item; index: number }> = ({ item, index }) => {
+const SwipeableRow: FunctionComponent<{ item: Item; index: number }> = ({ item, index }) => {
if (index % 2 === 0) {
return (
@@ -31,25 +31,23 @@ const SwipeableRow: React.FunctionComponent<{ item: Item; index: number }> = ({
}
};
-export default class GestureHandlerSwipeableScreen extends Component {
- static navigationOptions = {
- title: 'Swipeable Rows',
- };
-
- render() {
- return (
- }
- renderItem={({ item, index }: { item: Item; index: number }) => (
-
- )}
- keyExtractor={(_, index) => index.toString()}
- />
- );
- }
+export default function GestureHandlerSwipeableScreen() {
+ return (
+ }
+ renderItem={({ item, index }: { item: Item; index: number }) => (
+
+ )}
+ keyExtractor={(_, index) => index.toString()}
+ />
+ );
}
+GestureHandlerSwipeableScreen.navigationOptions = {
+ title: 'Swipeable Rows',
+};
+
const styles = StyleSheet.create({
rectButton: {
flex: 1,
diff --git a/apps/native-component-list/src/screens/GifScreen.tsx b/apps/native-component-list/src/screens/GifScreen.tsx
index f0e0f4a80d2e6..843d52a3c5303 100644
--- a/apps/native-component-list/src/screens/GifScreen.tsx
+++ b/apps/native-component-list/src/screens/GifScreen.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { Image, View } from 'react-native';
export default function GifScreen() {
diff --git a/apps/native-component-list/src/screens/HTMLElementsScreen.tsx b/apps/native-component-list/src/screens/HTMLElementsScreen.tsx
index fd33d108063ab..c12a8d6b350e9 100644
--- a/apps/native-component-list/src/screens/HTMLElementsScreen.tsx
+++ b/apps/native-component-list/src/screens/HTMLElementsScreen.tsx
@@ -37,7 +37,6 @@ import {
UL,
} from '@expo/html-elements';
import View from '@expo/html-elements/build/primitives/View';
-import React from 'react';
import { ScrollView } from 'react-native';
function CustomArticle({ title, children }: any) {
@@ -170,30 +169,28 @@ const preformattedText = `body {
color: red;
}`;
-export default class HTMLScreen extends React.Component {
- static navigationOptions = {
- title: 'HTML',
- };
-
- render() {
- return (
-
-
+export default function HTMLScreen() {
+ return (
+
+
-
-
-
-
-
-
-
-
-
-
- );
- }
+
+
+
+
+
+
+
+
+
+
+ );
}
+
+HTMLScreen.navigationOptions = {
+ title: 'HTML',
+};
diff --git a/apps/native-component-list/src/screens/HapticsScreen.tsx b/apps/native-component-list/src/screens/HapticsScreen.tsx
index 8081aeec5c4c8..658162cc55e2f 100644
--- a/apps/native-component-list/src/screens/HapticsScreen.tsx
+++ b/apps/native-component-list/src/screens/HapticsScreen.tsx
@@ -1,6 +1,5 @@
import * as Haptics from 'expo-haptics';
-import React from 'react';
-import { SectionList, SectionListData, StyleSheet, Text, View, ViewStyle } from 'react-native';
+import { SectionList, SectionListData, StyleSheet, Text, View } from 'react-native';
import Button from '../components/Button';
import MonoText from '../components/MonoText';
@@ -59,12 +58,8 @@ const sections: SectionListData[] = [
},
];
-export default class HapticsScreen extends React.Component {
- static navigationOptions = {
- title: 'Haptics Feedback',
- };
-
- renderItem = ({
+export default function HapticsScreen() {
+ const renderItem = ({
item,
section: { method },
}: {
@@ -72,76 +67,60 @@ export default class HapticsScreen extends React.Component {
section: { method: (type: string) => void };
}) => ;
- renderSectionHeader = ({ section: { methodName } }: { section: { methodName: string } }) => (
-
+ const renderSectionHeader = ({
+ section: { methodName },
+ }: {
+ section: { methodName: string };
+ }) => (
+
+ {methodName}
+
);
- keyExtractor = (data: SectionData) => {
- if ('accessor' in data && 'value' in data) {
- return `key-${data.accessor}-${data.value}`;
- }
- return 'key-undefined';
- };
-
- render() {
- return (
-
-
- style={styles.list}
- sections={sections}
- renderItem={this.renderItem as any}
- renderSectionHeader={this.renderSectionHeader as any}
- keyExtractor={this.keyExtractor}
- />
-
- );
- }
+ return (
+
+ {
+ if ('accessor' in data && 'value' in data) {
+ return `key-${data.accessor}-${data.value}`;
+ }
+ return 'key-undefined';
+ }}
+ />
+
+ );
}
-class Item extends React.Component<{
+HapticsScreen.navigationOptions = {
+ title: 'Haptics Feedback',
+};
+
+function Item({
+ method,
+ type: { value, accessor },
+}: {
method: (type: string) => void;
type: { accessor: string; value: any };
-}> {
- get code() {
- const {
- method,
- type: { accessor },
- } = this.props;
- return `Haptics.${method.name}(${accessor || ''})`;
- }
- render() {
- const {
- method,
- type: { value },
- } = this.props;
+}) {
+ return (
+
+
+ );
}
const styles = StyleSheet.create({
diff --git a/apps/native-component-list/src/screens/Image/ImageTestView.tsx b/apps/native-component-list/src/screens/Image/ImageTestView.tsx
index e60623bb8ace3..6a94b78e0e588 100644
--- a/apps/native-component-list/src/screens/Image/ImageTestView.tsx
+++ b/apps/native-component-list/src/screens/Image/ImageTestView.tsx
@@ -1,30 +1,29 @@
-import * as React from 'react';
import { StyleSheet, View, ViewStyle } from 'react-native';
import { defaultImage } from './images';
import { ImageTestComponent, ImageTestProps } from './types';
-type PropsType = {
+export default function ImageTestView({
+ imageProps,
+ ImageComponent,
+ loadOnDemand,
+ ...props
+}: {
style?: ViewStyle;
imageProps: ImageTestProps;
ImageComponent: ImageTestComponent;
loadOnDemand?: boolean;
-};
-
-export default class ImageTestView extends React.PureComponent {
- render() {
- const { imageProps, ImageComponent, loadOnDemand } = this.props;
- const { style, source, ...otherImageProps } = imageProps;
- return (
-
-
-
- );
- }
+}) {
+ const { style, source, ...otherImageProps } = imageProps;
+ return (
+
+
+
+ );
}
const styles = StyleSheet.create({
diff --git a/apps/native-component-list/src/screens/Image/images/defaultImage.web.ts b/apps/native-component-list/src/screens/Image/images/defaultImage.web.ts
deleted file mode 100644
index c67906e241e6c..0000000000000
--- a/apps/native-component-list/src/screens/Image/images/defaultImage.web.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-const defaultImage = require('../../../../assets/images/expo-icon@3x.png');
-
-export default defaultImage;
diff --git a/apps/native-component-list/src/screens/ImageManipulatorScreen.tsx b/apps/native-component-list/src/screens/ImageManipulatorScreen.tsx
index ebf05151a6b4d..98a90ead2d9d9 100644
--- a/apps/native-component-list/src/screens/ImageManipulatorScreen.tsx
+++ b/apps/native-component-list/src/screens/ImageManipulatorScreen.tsx
@@ -1,8 +1,8 @@
-import Ionicons from '@expo/vector-icons/build/Ionicons';
+import Ionicons from '@expo/vector-icons/Ionicons';
import { Asset } from 'expo-asset';
import * as ImageManipulator from 'expo-image-manipulator';
import * as ImagePicker from 'expo-image-picker';
-import React from 'react';
+import React, { useEffect, useReducer } from 'react';
import {
Image,
ScrollView,
@@ -21,100 +21,41 @@ interface State {
original?: Asset;
}
-// See: https://github.com/expo/expo/pull/10229#discussion_r490961694
-// eslint-disable-next-line @typescript-eslint/ban-types
-export default class ImageManipulatorScreen extends React.Component<{}, State> {
- static navigationOptions = {
- title: 'ImageManipulator',
- };
+ImageManipulatorScreen.navigationOptions = {
+ title: 'ImageManipulator',
+};
- readonly state: State = {
+export default function ImageManipulatorScreen() {
+ const [state, setState] = useReducer((s: State, a: Partial) => ({ ...s, ...a }), {
ready: false,
- };
+ });
- componentDidMount() {
+ useEffect(() => {
const image = Asset.fromModule(require('../../assets/images/example2.jpg'));
image.downloadAsync().then(() => {
- this.setState({
+ setState({
ready: true,
image,
original: image,
});
});
- }
+ }, []);
- render() {
- return (
-
-
-
- this._rotate(90)}>
- 90
-
- this._rotate(45)}>
- 45
-
- this._rotate(-90)}>
- -90
-
- this._flip(ImageManipulator.FlipType.Horizontal)}>
- Flip horizontal
-
- this._flip(ImageManipulator.FlipType.Vertical)}>
- Flip vertical
-
- this._resize({ width: 250 })}>
- Resize width
-
- this._resize({ width: 300, height: 300 })}>
- Resize both to square
-
- this._compress(0.1)}>
- 90% compression
-
-
- Crop - half image
-
-
- Cccombo
-
-
-
- {this.state.ready && this._renderImage()}
-
-
- Pick a photo
-
-
- Reset photo
-
-
-
-
- );
- }
-
- _renderImage = () => {
- const height =
- this.state.image?.height && this.state.image?.height < 300 ? this.state.image?.height : 300;
- const width =
- this.state.image?.width && this.state.image?.width < 300 ? this.state.image?.width : 300;
+ const renderImage = () => {
+ const height = state.image?.height && state.image?.height < 300 ? state.image?.height : 300;
+ const width = state.image?.width && state.image?.width < 300 ? state.image?.width : 300;
return (
);
};
- _pickPhoto = async () => {
+ const pickPhoto = async () => {
const { status } = await ImagePicker.requestMediaLibraryPermissionsAsync();
if (status !== 'granted') {
alert('Permission to MEDIA_LIBRARY not granted!');
@@ -127,71 +68,110 @@ export default class ImageManipulatorScreen extends React.Component<{}, State> {
alert('No image selected!');
return;
}
- this.setState({ image: result.assets[0] });
+ setState({ image: result.assets[0] });
};
- _rotate = async (deg: number) => {
- await this._manipulate([{ rotate: deg }], {
+ const rotate = async (deg: number) =>
+ await manipulate([{ rotate: deg }], {
format: ImageManipulator.SaveFormat.PNG,
});
- };
- _resize = async (size: { width?: number; height?: number }) => {
- await this._manipulate([{ resize: size }]);
- };
+ const resize = async (size: { width?: number; height?: number }) =>
+ await manipulate([{ resize: size }]);
- _flip = async (flip: ImageManipulator.FlipType) => {
- await this._manipulate([{ flip }]);
- };
+ const flip = async (flip: ImageManipulator.FlipType) => await manipulate([{ flip }]);
- _compress = async (compress: number) => {
- await this._manipulate([], { compress });
- };
+ const compress = async (compress: number) => await manipulate([], { compress });
- _crop = async () => {
- await this._manipulate([
+ const crop = async () =>
+ await manipulate([
{
crop: {
originX: 0,
originY: 0,
- width: this.state.image!.width! / 2,
- height: this.state.image!.height!,
+ width: state.image!.width! / 2,
+ height: state.image!.height!,
},
},
]);
- };
- _combo = async () => {
- await this._manipulate([
+ const combo = async () =>
+ await manipulate([
{ rotate: 180 },
{ flip: ImageManipulator.FlipType.Vertical },
{
crop: {
- originX: this.state.image!.width! / 4,
- originY: this.state.image!.height! / 4,
- width: this.state.image!.width! / 2,
- height: this.state.image!.width! / 2,
+ originX: state.image!.width! / 4,
+ originY: state.image!.height! / 4,
+ width: state.image!.width! / 2,
+ height: state.image!.width! / 2,
},
},
]);
- };
- _reset = () => {
- this.setState((state) => ({ image: state.original }));
- };
+ const reset = () => setState({ image: state.original });
- _manipulate = async (
+ const manipulate = async (
actions: ImageManipulator.Action[],
saveOptions?: ImageManipulator.SaveOptions
) => {
- const { image } = this.state;
+ const { image } = state;
const manipResult = await ImageManipulator.manipulateAsync(
(image! as Asset).localUri || image!.uri,
actions,
saveOptions
);
- this.setState({ image: manipResult });
+ setState({ image: manipResult });
};
+
+ return (
+
+
+
+ rotate(90)}>
+ 90
+
+ rotate(45)}>
+ 45
+
+ rotate(-90)}>
+ -90
+
+ flip(ImageManipulator.FlipType.Horizontal)}>
+ Flip horizontal
+
+ flip(ImageManipulator.FlipType.Vertical)}>
+ Flip vertical
+
+ resize({ width: 250 })}>
+ Resize width
+
+ resize({ width: 300, height: 300 })}>
+ Resize both to square
+
+ compress(0.1)}>
+ 90% compression
+
+
+ Crop - half image
+
+
+ Cccombo
+
+
+
+ {state.ready && renderImage()}
+
+
+ Pick a photo
+
+
+ Reset photo
+
+
+
+
+ );
}
const Button: React.FunctionComponent = ({ onPress, style, children }) => (
diff --git a/apps/native-component-list/src/screens/KeepAwakeScreen.tsx b/apps/native-component-list/src/screens/KeepAwakeScreen.tsx
index 4436d88f8fd12..67dd5c52f2832 100644
--- a/apps/native-component-list/src/screens/KeepAwakeScreen.tsx
+++ b/apps/native-component-list/src/screens/KeepAwakeScreen.tsx
@@ -1,28 +1,25 @@
import * as KeepAwake from 'expo-keep-awake';
-import React from 'react';
import { View } from 'react-native';
import Button from '../components/Button';
-export default class KeepAwakeScreen extends React.Component {
- static navigationOptions = {
- title: 'KeepAwake',
- };
-
- _activate = () => {
+export default function KeepAwakeScreen() {
+ const _activate = () => {
KeepAwake.activateKeepAwakeAsync();
};
- _deactivate = () => {
+ const _deactivate = () => {
KeepAwake.deactivateKeepAwake();
};
- render() {
- return (
-
-
-
-
- );
- }
+ return (
+
+
+
+
+ );
}
+
+KeepAwakeScreen.navigationOptions = {
+ title: 'KeepAwake',
+};
diff --git a/apps/native-component-list/src/screens/LinearGradientScreen.tsx b/apps/native-component-list/src/screens/LinearGradientScreen.tsx
index e603b1375922c..cd2085809f25d 100644
--- a/apps/native-component-list/src/screens/LinearGradientScreen.tsx
+++ b/apps/native-component-list/src/screens/LinearGradientScreen.tsx
@@ -1,5 +1,5 @@
import { LinearGradient } from 'expo-linear-gradient';
-import React from 'react';
+import React, { useEffect } from 'react';
import { Image, Platform, Animated, ScrollView, StyleSheet, Text, View } from 'react-native';
import MonoText from '../components/MonoText';
@@ -13,64 +13,45 @@ function incrementColor(color: string, step: number) {
return `#${'0'.repeat(6 - newIntColor.length)}${newIntColor}`;
}
-type State = {
- count: number;
- colorTop: string;
- colorBottom: string;
-};
-
-// See: https://github.com/expo/expo/pull/10229#discussion_r490961694
-// eslint-disable-next-line @typescript-eslint/ban-types
-export default class LinearGradientScreen extends React.Component<{}, State> {
- static navigationOptions = {
- title: 'LinearGradient',
- };
-
- state = {
- count: 0,
- colorTop: '#000000',
- colorBottom: '#cccccc',
- };
-
- _interval?: ReturnType;
+export default function LinearGradientScreen() {
+ const [count, setCount] = React.useState(0);
+ const [colorTop, setColorTop] = React.useState('#000000');
+ const [colorBottom, setColorBottom] = React.useState('#cccccc');
- componentDidMount() {
- this._interval = setInterval(() => {
- this.setState((state) => ({
- count: state.count + 1,
- colorTop: incrementColor(state.colorTop, 1),
- colorBottom: incrementColor(state.colorBottom, -1),
- }));
+ useEffect(() => {
+ const interval = setInterval(() => {
+ setCount((count) => count + 1);
+ setColorTop((colorTop) => incrementColor(colorTop, 1));
+ setColorBottom((colorBottom) => incrementColor(colorBottom, -1));
}, 100);
- }
- componentWillUnmount() {
- clearInterval(this._interval);
- }
+ return () => {
+ clearInterval(interval);
+ };
+ }, []);
- render() {
- const location = Math.sin(this.state.count / 100) * 0.5;
- const position = Math.sin(this.state.count / 100);
- return (
-
-
-
-
-
- {Platform.OS !== 'web' && }
-
- );
- }
+ const location = Math.sin(count / 100) * 0.5;
+ const position = Math.sin(count / 100);
+ return (
+
+
+
+
+
+ {Platform.OS !== 'web' && }
+
+ );
}
+LinearGradientScreen.navigationOptions = {
+ title: 'LinearGradient',
+};
+
const Container: React.FunctionComponent<{ title: string; children?: React.ReactNode }> = ({
title,
children,
diff --git a/apps/native-component-list/src/screens/LocalizationScreen.tsx b/apps/native-component-list/src/screens/LocalizationScreen.tsx
index 9e175f3566831..5c2ef628220fc 100644
--- a/apps/native-component-list/src/screens/LocalizationScreen.tsx
+++ b/apps/native-component-list/src/screens/LocalizationScreen.tsx
@@ -1,8 +1,7 @@
import { Picker } from '@react-native-picker/picker';
import * as Localization from 'expo-localization';
import i18n from 'i18n-js';
-import chunk from 'lodash/chunk';
-import React from 'react';
+import { useReducer } from 'react';
import { ScrollView, StyleSheet, Text, View } from 'react-native';
import DeprecatedHeading from '../components/DeprecatedHeading';
@@ -42,38 +41,44 @@ function HooksLocalizationSection() {
);
}
-// See: https://github.com/expo/expo/pull/10229#discussion_r490961694
-// eslint-disable-next-line @typescript-eslint/ban-types
-export default class LocalizationScreen extends React.Component<{}, State> {
- static navigationOptions = {
- title: 'Localization',
- };
+function lodashChunk(array: any[], size: number) {
+ const chunked = [];
+ for (let i = 0; i < array.length; i += size) {
+ chunked.push(array.slice(i, i + size));
+ }
+ return chunked;
+}
- readonly state: State = {
+LocalizationScreen.navigationOptions = {
+ title: 'Localization',
+};
+
+export default function LocalizationScreen() {
+ const [state, setState] = useReducer((s: State, a: Partial) => ({ ...s, ...a }), {
currentLocale: Localization.locale,
preferredLocales: Localization.locales,
isoCurrencyCodes: Localization.isoCurrencyCodes,
- };
+ });
- queryPreferredLocales = async () => {
+ const queryPreferredLocales = async () => {
const preferredLocales = Localization.locales;
const currentLocale = Localization.locale;
- this.setState({ preferredLocales, currentLocale });
+ setState({ preferredLocales, currentLocale });
};
- queryCurrencyCodes = async () => {
- if (this.state.isoCurrencyCodes.length === 0) {
+ const queryCurrencyCodes = async () => {
+ if (state.isoCurrencyCodes.length === 0) {
const isoCurrencyCodes = Localization.isoCurrencyCodes;
- this.setState({ isoCurrencyCodes });
+ setState({ isoCurrencyCodes });
}
};
- prettyFormatCurrency = () => {
+ const prettyFormatCurrency = () => {
let buffer = '';
let seenCount = 0;
- const sample = this.state.isoCurrencyCodes.slice(0, 100);
- const grouped = chunk(sample, 10);
- let drilldownIndex = 0;
+ const sample = state.isoCurrencyCodes.slice(0, 100);
+ const grouped = lodashChunk(sample, 10);
+ let drillDownIndex = 0;
let currentColumn = 0;
while (true) {
while (true) {
@@ -81,69 +86,68 @@ export default class LocalizationScreen extends React.Component<{}, State> {
if (currentColumn === grouped.length) {
currentColumn = 0;
buffer += '\n';
- drilldownIndex++;
+ drillDownIndex++;
continue;
}
- buffer += `${grouped[currentColumn][drilldownIndex]}\t`;
+ buffer += `${grouped[currentColumn][drillDownIndex]}\t`;
seenCount++;
currentColumn++;
}
}
};
- changeLocale = (locale: string) => {
+ const changeLocale = (locale: string) => {
i18n.locale = locale;
- this.setState({ locale });
+ setState({ locale });
};
- render() {
- return (
-
-
-
-
- Locales in Preference Order
- {JSON.stringify(Localization.getLocales(), null, 2)}
-
- Calendars in Preference Order
- {JSON.stringify(Localization.getCalendars(), null, 2)}
-
- Localization Table
- this.changeLocale(`${value}`)}>
-
-
-
-
-
-
- Exists in Both:
- {this.state.currentLocale ? i18n.t('phrase') : ''}
-
-
- Default Case Only:
- {this.state.currentLocale ? i18n.t('default') : ''}
-
-
- Current Locale
- {JSON.stringify(this.state.currentLocale, null, 2)}
- Locales in Preference Order
-
- {this.state.preferredLocales && this.state.preferredLocales.length > 0 && (
- {JSON.stringify(this.state.preferredLocales, null, 2)}
- )}
-
- Currency Codes
-
- {this.state.isoCurrencyCodes && this.state.isoCurrencyCodes.length > 0 && (
- {this.prettyFormatCurrency()}
- )}
+ return (
+
+
+
+
+ Locales in Preference Order
+ {JSON.stringify(Localization.getLocales(), null, 2)}
+
+ Calendars in Preference Order
+ {JSON.stringify(Localization.getCalendars(), null, 2)}
+
+ Localization Table
+ changeLocale(`${value}`)}>
+
+
+
+
+
+
+ Exists in Both:
+ {state.currentLocale ? i18n.t('phrase') : ''}
+
+
+ Default Case Only:
+ {state.currentLocale ? i18n.t('default') : ''}
+
-
- );
- }
+
+ Current Locale
+ {JSON.stringify(state.currentLocale, null, 2)}
+ Locales in Preference Order
+
+ {state.preferredLocales && state.preferredLocales.length > 0 && (
+ {JSON.stringify(state.preferredLocales, null, 2)}
+ )}
+
+ Currency Codes
+
+ {state.isoCurrencyCodes && state.isoCurrencyCodes.length > 0 && (
+ {prettyFormatCurrency()}
+ )}
+
+
+ );
}
const styles = StyleSheet.create({
row: {
diff --git a/apps/native-component-list/src/screens/Location/BackgroundLocationMapScreen.tsx b/apps/native-component-list/src/screens/Location/BackgroundLocationMapScreen.tsx
index 80d9c4cd44b03..175bcd05bc599 100644
--- a/apps/native-component-list/src/screens/Location/BackgroundLocationMapScreen.tsx
+++ b/apps/native-component-list/src/screens/Location/BackgroundLocationMapScreen.tsx
@@ -1,5 +1,5 @@
-import FontAwesome from '@expo/vector-icons/build/FontAwesome';
-import MaterialIcons from '@expo/vector-icons/build/MaterialIcons';
+import FontAwesome from '@expo/vector-icons/FontAwesome';
+import MaterialIcons from '@expo/vector-icons/MaterialIcons';
import AsyncStorage from '@react-native-async-storage/async-storage';
import { useFocusEffect } from '@react-navigation/native';
import { StackNavigationProp } from '@react-navigation/stack';
diff --git a/apps/native-component-list/src/screens/Location/LocationScreen.tsx b/apps/native-component-list/src/screens/Location/LocationScreen.tsx
index 50b7ac0c7786d..a53c1c3453b43 100644
--- a/apps/native-component-list/src/screens/Location/LocationScreen.tsx
+++ b/apps/native-component-list/src/screens/Location/LocationScreen.tsx
@@ -38,89 +38,80 @@ function SubscriptionDemo(props: SubscriptionDemoProps) {
return ;
}
-export default class LocationScreen extends React.Component<{
+export default function LocationScreen({
+ navigation,
+}: {
navigation: StackNavigationProp<{ BackgroundLocationMap: undefined; Geofencing: undefined }>;
-}> {
- static navigationOptions = {
- title: 'Location',
- };
+}) {
+ return (
+
+ Location.requestPermissionsAsync()}
+ />
+ Location.getPermissionsAsync()}
+ />
+ Location.requestForegroundPermissionsAsync()}
+ />
+ Location.getForegroundPermissionsAsync()}
+ />
+ Location.requestBackgroundPermissionsAsync()}
+ />
+ Location.getBackgroundPermissionsAsync()}
+ />
+ Location.hasServicesEnabledAsync()}
+ />
+ Location.getProviderStatusAsync()}
+ />
+
+ Location.getCurrentPositionAsync({ accuracy: Location.LocationAccuracy.Lowest })
+ }
+ />
+ Location.getCurrentPositionAsync()}
+ />
+ Location.getLastKnownPositionAsync()}
+ />
+ Location.watchPositionAsync({}, setValue)}
+ />
+ Location.getHeadingAsync()} />
+ Location.watchHeadingAsync(setValue)}
+ />
- _goToGeofencingMap = () => {
- this.props.navigation.navigate('Geofencing');
- };
-
- renderLocationMapButton() {
- return (
-
+ navigation.navigate('Geofencing')} title="Geofencing map" />
- );
- }
-
- render() {
- return (
-
- Location.requestPermissionsAsync()}
- />
- Location.getPermissionsAsync()}
- />
- Location.requestForegroundPermissionsAsync()}
- />
- Location.getForegroundPermissionsAsync()}
- />
- Location.requestBackgroundPermissionsAsync()}
- />
- Location.getBackgroundPermissionsAsync()}
- />
- Location.hasServicesEnabledAsync()}
- />
- Location.getProviderStatusAsync()}
- />
-
- Location.getCurrentPositionAsync({ accuracy: Location.LocationAccuracy.Lowest })
- }
- />
- Location.getCurrentPositionAsync()}
- />
- Location.getLastKnownPositionAsync()}
- />
- Location.watchPositionAsync({}, setValue)}
- />
- Location.getHeadingAsync()} />
- Location.watchHeadingAsync(setValue)}
- />
- {this.renderLocationMapButton()}
-
- );
- }
+
+ );
}
+LocationScreen.navigationOptions = {
+ title: 'Location',
+};
+
const styles = StyleSheet.create({
scrollView: {
paddingTop: 10,
diff --git a/apps/native-component-list/src/screens/MapsScreen.web.tsx b/apps/native-component-list/src/screens/MapsScreen.web.tsx
index 71e0521b49bf2..ea17f77c4fe8b 100644
--- a/apps/native-component-list/src/screens/MapsScreen.web.tsx
+++ b/apps/native-component-list/src/screens/MapsScreen.web.tsx
@@ -1,4 +1 @@
-import * as React from 'react';
-import { Text } from 'react-native';
-
-export default () => Map View is not implemented on web;
+export default () => Map View is not implemented on web
;
diff --git a/apps/native-component-list/src/screens/MaskedViewScreen.tsx b/apps/native-component-list/src/screens/MaskedViewScreen.tsx
index eb90849c8c8dd..cc6718e359d90 100644
--- a/apps/native-component-list/src/screens/MaskedViewScreen.tsx
+++ b/apps/native-component-list/src/screens/MaskedViewScreen.tsx
@@ -1,32 +1,21 @@
import MaskedView from '@react-native-masked-view/masked-view';
-import React from 'react';
+import React, { useEffect } from 'react';
import { Animated, Easing, Image, View } from 'react-native';
const AnimatedMaskView = Animated.createAnimatedComponent(MaskedView);
-interface State {
- text: string;
-}
-
-// See: https://github.com/expo/expo/pull/10229#discussion_r490961694
-// eslint-disable-next-line @typescript-eslint/ban-types
-export default class MaskedViewScreen extends React.Component<{}, State> {
- static navigationOptions = {
- title: 'Basic Mask Example',
- };
-
- readonly state: State = {
- text: '100',
- };
+MaskedViewScreen.navigationOptions = {
+ title: 'Basic Mask Example',
+};
+export default function MaskedViewScreen() {
+ const [text, setText] = React.useState(100);
- _animatedTextValue: Animated.Value = new Animated.Value(0);
- _animatedScaleValue: Animated.Value = new Animated.Value(0);
+ const animatedTextValue = React.useRef(new Animated.Value(0));
+ const animatedScaleValue = React.useRef(new Animated.Value(0));
- _interval?: ReturnType;
-
- componentDidMount() {
+ useEffect(() => {
Animated.loop(
- Animated.timing(this._animatedTextValue, {
+ Animated.timing(animatedTextValue.current, {
useNativeDriver: false,
toValue: 360,
duration: 100,
@@ -34,84 +23,80 @@ export default class MaskedViewScreen extends React.Component<{}, State> {
})
).start();
- this._animatedScaleValue = new Animated.Value(1);
+ animatedScaleValue.current = new Animated.Value(1);
+
Animated.loop(
Animated.sequence([
- Animated.timing(this._animatedScaleValue, {
+ Animated.timing(animatedScaleValue.current, {
duration: 1000,
toValue: 1.5,
useNativeDriver: true,
}),
- Animated.timing(this._animatedScaleValue, {
+ Animated.timing(animatedScaleValue.current, {
duration: 1000,
toValue: 1,
useNativeDriver: true,
}),
])
).start();
+ }, []);
- let counter = 100;
- this._interval = setInterval(() => {
- counter++;
- this.setState({
- text: `${counter}`,
- });
+ useEffect(() => {
+ const interval = setInterval(() => {
+ setText((text) => text + 1);
}, 1000);
- }
- componentWillUnmount() {
- if (this._interval) {
- clearInterval(this._interval);
- }
- }
+ return () => {
+ clearInterval(interval);
+ };
+ }, []);
// NOTE(brentvatne): this doesn't work properly on Android yet
- render() {
- const width = 240;
- const height = 200;
- return (
-
-
+
+
+
-
-
- {this.state.text}
-
-
- }>
-
-
-
- );
- }
+ {text}
+
+
+ }>
+
+
+
+ );
}
diff --git a/apps/native-component-list/src/screens/MaskedViewScreen.web.tsx b/apps/native-component-list/src/screens/MaskedViewScreen.web.tsx
index b38d39d21d848..5acfc1094843a 100644
--- a/apps/native-component-list/src/screens/MaskedViewScreen.web.tsx
+++ b/apps/native-component-list/src/screens/MaskedViewScreen.web.tsx
@@ -1,4 +1 @@
-import * as React from 'react';
-import { Text } from 'react-native';
-
-export default () => Mask view is not implemented on web;
+export default () => Mask view is not implemented on web
;
diff --git a/apps/native-component-list/src/screens/MediaLibrary/MediaLibraryCell.tsx b/apps/native-component-list/src/screens/MediaLibrary/MediaLibraryCell.tsx
index eb1f01e093b4f..05029a4eeb3e9 100644
--- a/apps/native-component-list/src/screens/MediaLibrary/MediaLibraryCell.tsx
+++ b/apps/native-component-list/src/screens/MediaLibrary/MediaLibraryCell.tsx
@@ -1,20 +1,19 @@
-import FontAwesome from '@expo/vector-icons/build/FontAwesome';
+import FontAwesome from '@expo/vector-icons/FontAwesome';
import { Image } from 'expo-image';
import * as MediaLibrary from 'expo-media-library';
import React from 'react';
import { StyleProp, StyleSheet, Text, TouchableOpacity, View, ViewStyle } from 'react-native';
-export default class MediaLibraryCell extends React.Component<{
+export default function MediaLibraryCell({
+ asset,
+ onPress,
+ style,
+}: {
asset: MediaLibrary.Asset;
onPress: (asset: MediaLibrary.Asset) => void;
style?: StyleProp;
-}> {
- onPress = () => {
- const { asset } = this.props;
- this.props.onPress(asset);
- };
-
- getAssetData(asset: MediaLibrary.Asset) {
+}) {
+ const data = (() => {
switch (asset.mediaType) {
case MediaLibrary.MediaType.photo:
return {
@@ -41,24 +40,19 @@ export default class MediaLibraryCell extends React.Component<{
default:
return null;
}
- }
-
- render() {
- const { asset, style } = this.props;
- const data = this.getAssetData(asset);
+ })();
- return (
-
- {data && data.preview}
- {data && (
-
-
- {data.description}
-
- )}
-
- );
- }
+ return (
+ onPress(asset)}>
+ {data && data.preview}
+ {data && (
+
+
+ {data.description}
+
+ )}
+
+ );
}
const styles = StyleSheet.create({
diff --git a/apps/native-component-list/src/screens/ModalScreen.tsx b/apps/native-component-list/src/screens/ModalScreen.tsx
index 47de36d27f1ff..0303f0d13e87a 100644
--- a/apps/native-component-list/src/screens/ModalScreen.tsx
+++ b/apps/native-component-list/src/screens/ModalScreen.tsx
@@ -1,4 +1,4 @@
-import * as React from 'react';
+import { useReducer } from 'react';
import { Modal, StyleSheet, Text, View } from 'react-native';
import Button from '../components/Button';
@@ -9,71 +9,69 @@ interface State {
animationType?: 'none' | 'slide' | 'fade';
}
-export default class ModalScreen extends React.Component