diff --git a/.eslintrc.json b/.eslintrc.json index 7eb64a72542..39cdbb61165 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -12,6 +12,7 @@ "extends": ["plugin:mdx/recommended"] } ], + "parser": "@typescript-eslint/parser", "parserOptions": { "sourceType": "module", "ecmaVersion": "latest", diff --git a/.github/workflows/pre-merge.yml b/.github/workflows/pre-merge.yml index ee2df88a33b..6ec27a89952 100644 --- a/.github/workflows/pre-merge.yml +++ b/.github/workflows/pre-merge.yml @@ -9,12 +9,15 @@ jobs: lint: runs-on: ubuntu-latest steps: - - name: Set up Node.js - uses: actions/setup-node@v4 - - name: Checkout repository uses: actions/checkout@v4 + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: "20" + cache: "yarn" + - name: Install dependencies run: yarn install --frozen-lockfile --no-progress --non-interactive @@ -25,12 +28,15 @@ jobs: build: runs-on: ubuntu-latest steps: - - name: Set up Node.js - uses: actions/setup-node@v4 - - name: Checkout repository uses: actions/checkout@v4 + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: "20" + cache: "yarn" + - name: Install dependencies run: yarn install --frozen-lockfile --no-progress --non-interactive @@ -38,4 +44,4 @@ jobs: run: yarn build working-directory: website env: - NODE_OPTIONS: "--max_old_space_size=4096" + NODE_OPTIONS: "--max_old_space_size=8192" diff --git a/.prettierrc b/.prettierrc.json similarity index 93% rename from .prettierrc rename to .prettierrc.json index 11998292dbf..8772ae7f1ce 100644 --- a/.prettierrc +++ b/.prettierrc.json @@ -1,7 +1,7 @@ { "overrides": [ { - "files": "*.js", + "files": ["*.js", "*.jsx", "*.ts", "*.tsx"], "options": { "arrowParens": "avoid", "bracketSpacing": false, diff --git a/docs/_fabric-native-components.jsx b/docs/_fabric-native-components.jsx index 5efc9bf5945..fc6a3171a4f 100644 --- a/docs/_fabric-native-components.jsx +++ b/docs/_fabric-native-components.jsx @@ -1,6 +1,6 @@ -import React from "react"; -import IOSContent from "./fabric-native-components-ios.md"; -import AndroidContent from "./fabric-native-components-android.md"; +import React from 'react'; +import IOSContent from './fabric-native-components-ios.md'; +import AndroidContent from './fabric-native-components-android.md'; export function FabricNativeComponentsIOS() { return ; diff --git a/docs/_getting-started-linux-android.md b/docs/_getting-started-linux-android.md index 58cb9de2622..410a33de479 100644 --- a/docs/_getting-started-linux-android.md +++ b/docs/_getting-started-linux-android.md @@ -32,18 +32,18 @@ Once setup has finalized and you're presented with the Welcome screen, proceed t

2. Install the Android SDK

-Android Studio installs the latest Android SDK by default. Building a React Native app with native code, however, requires the `Android 14 (UpsideDownCake)` SDK in particular. Additional Android SDKs can be installed through the SDK Manager in Android Studio. +Android Studio installs the latest Android SDK by default. Building a React Native app with native code, however, requires the `Android 15 (VanillaIceCream)` SDK in particular. Additional Android SDKs can be installed through the SDK Manager in Android Studio. To do that, open Android Studio, click on "Configure" button and select "SDK Manager". > The SDK Manager can also be found within the Android Studio "Settings" dialog, under **Languages & Frameworks** → **Android SDK**. -Select the "SDK Platforms" tab from within the SDK Manager, then check the box next to "Show Package Details" in the bottom right corner. Look for and expand the `Android 14 (UpsideDownCake)` entry, then make sure the following items are checked: +Select the "SDK Platforms" tab from within the SDK Manager, then check the box next to "Show Package Details" in the bottom right corner. Look for and expand the `Android 15 (VanillaIceCream)` entry, then make sure the following items are checked: -- `Android SDK Platform 34` +- `Android SDK Platform 35` - `Intel x86 Atom_64 System Image` or `Google APIs Intel x86 Atom System Image` -Next, select the "SDK Tools" tab and check the box next to "Show Package Details" here as well. Look for and expand the "Android SDK Build-Tools" entry, then make sure that `34.0.0` is selected. +Next, select the "SDK Tools" tab and check the box next to "Show Package Details" here as well. Look for and expand the "Android SDK Build-Tools" entry, then make sure that `35.0.0` is selected. Finally, click "Apply" to download and install the Android SDK and related build tools. @@ -87,7 +87,7 @@ If you use Android Studio to open `./AwesomeProject/android`, you can see the li ![Android Studio AVD Manager](/docs/assets/GettingStartedAndroidStudioAVD.png) -If you have recently installed Android Studio, you will likely need to [create a new AVD](https://developer.android.com/studio/run/managing-avds.html). Select "Create Virtual Device...", then pick any Phone from the list and click "Next", then select the **UpsideDownCake** API Level 34 image. +If you have recently installed Android Studio, you will likely need to [create a new AVD](https://developer.android.com/studio/run/managing-avds.html). Select "Create Virtual Device...", then pick any Phone from the list and click "Next", then select the **VanillaIceCream** API Level 35 image. > We recommend configuring [VM acceleration](https://developer.android.com/studio/run/emulator-acceleration.html#vm-linux) on your system to improve performance. Once you've followed those instructions, go back to the AVD Manager. diff --git a/docs/_getting-started-macos-android.md b/docs/_getting-started-macos-android.md index c067dc8a1e0..16d45441ac7 100644 --- a/docs/_getting-started-macos-android.md +++ b/docs/_getting-started-macos-android.md @@ -34,7 +34,7 @@ brew info --cask zulu@17 # Installed using the formulae.brew.sh API on 2024-06-06 at 10:00:00 # Navigate to the folder -finder /opt/homebrew/Caskroom/zulu@17/ # or /usr/local/Caskroom/zulu@17/ +open /opt/homebrew/Caskroom/zulu@17/ # or /usr/local/Caskroom/zulu@17/ ``` After opening Finder, double click the `Double-Click to Install Azul Zulu JDK 17.pkg` package to install the JDK. @@ -71,7 +71,7 @@ Once setup has finalized and you're presented with the Welcome screen, proceed t

2. Install the Android SDK

-Android Studio installs the latest Android SDK by default. Building a React Native app with native code, however, requires the `Android 14 (UpsideDownCake)` SDK in particular. Additional Android SDKs can be installed through the SDK Manager in Android Studio. +Android Studio installs the latest Android SDK by default. Building a React Native app with native code, however, requires the `Android 15 (VanillaIceCream)` SDK in particular. Additional Android SDKs can be installed through the SDK Manager in Android Studio. To do that, open Android Studio, click on "More Actions" button and select "SDK Manager". @@ -79,12 +79,12 @@ To do that, open Android Studio, click on "More Actions" button and select "SDK > The SDK Manager can also be found within the Android Studio "Settings" dialog, under **Languages & Frameworks** → **Android SDK**. -Select the "SDK Platforms" tab from within the SDK Manager, then check the box next to "Show Package Details" in the bottom right corner. Look for and expand the `Android 14 (UpsideDownCake)` entry, then make sure the following items are checked: +Select the "SDK Platforms" tab from within the SDK Manager, then check the box next to "Show Package Details" in the bottom right corner. Look for and expand the `Android 15 (VanillaIceCream)` entry, then make sure the following items are checked: -- `Android SDK Platform 34` +- `Android SDK Platform 35` - `Intel x86 Atom_64 System Image` or `Google APIs Intel x86 Atom System Image` or (for Apple M1 Silicon) `Google APIs ARM 64 v8a System Image` -Next, select the "SDK Tools" tab and check the box next to "Show Package Details" here as well. Look for and expand the "Android SDK Build-Tools" entry, then make sure that `34.0.0` is selected. +Next, select the "SDK Tools" tab and check the box next to "Show Package Details" here as well. Look for and expand the "Android SDK Build-Tools" entry, then make sure that `35.0.0` is selected. Finally, click "Apply" to download and install the Android SDK and related build tools. @@ -120,7 +120,7 @@ If you use Android Studio to open `./AwesomeProject/android`, you can see the li ![Android Studio AVD Manager](/docs/assets/GettingStartedAndroidStudioAVD.png) -If you have recently installed Android Studio, you will likely need to [create a new AVD](https://developer.android.com/studio/run/managing-avds.html). Select "Create Virtual Device...", then pick any Phone from the list and click "Next", then select the **UpsideDownCake** API Level 34 image. +If you have recently installed Android Studio, you will likely need to [create a new AVD](https://developer.android.com/studio/run/managing-avds.html). Select "Create Virtual Device...", then pick any Phone from the list and click "Next", then select the **VanillaIceCream** API Level 35 image. Click "Next" then "Finish" to create your AVD. At this point you should be able to click on the green triangle button next to your AVD to launch it. diff --git a/docs/_getting-started-macos-ios.md b/docs/_getting-started-macos-ios.md index 435b9543fd9..6b366fb64f4 100644 --- a/docs/_getting-started-macos-ios.md +++ b/docs/_getting-started-macos-ios.md @@ -33,7 +33,7 @@ You will also need to install the Xcode Command Line Tools. Open Xcode, then cho To install a simulator, open **Xcode > Settings... (or Preferences...)** and select the **Platforms (or Components)** tab. Select a simulator with the corresponding version of iOS you wish to use. -If you are using Xcode version 14.0 or greater than to install a simulator, open **Xcode > Settings > Platforms** tab, then click "+" icon and select **iOS…** option. +If you are using Xcode version 14.0 or greater to install a simulator, open **Xcode > Settings > Platforms** tab, then click "+" icon and select **iOS…** option. #### CocoaPods diff --git a/docs/_getting-started-windows-android.md b/docs/_getting-started-windows-android.md index 15d61eaa500..0ded094e8fc 100644 --- a/docs/_getting-started-windows-android.md +++ b/docs/_getting-started-windows-android.md @@ -45,7 +45,7 @@ Once setup has finalized and you're presented with the Welcome screen, proceed t

2. Install the Android SDK

-Android Studio installs the latest Android SDK by default. Building a React Native app with native code, however, requires the `Android 14 (UpsideDownCake)` SDK in particular. Additional Android SDKs can be installed through the SDK Manager in Android Studio. +Android Studio installs the latest Android SDK by default. Building a React Native app with native code, however, requires the `Android 15 (VanillaIceCream)` SDK in particular. Additional Android SDKs can be installed through the SDK Manager in Android Studio. To do that, open Android Studio, click on "More Actions" button and select "SDK Manager". @@ -53,12 +53,12 @@ To do that, open Android Studio, click on "More Actions" button and select "SDK > The SDK Manager can also be found within the Android Studio "Settings" dialog, under **Languages & Frameworks** → **Android SDK**. -Select the "SDK Platforms" tab from within the SDK Manager, then check the box next to "Show Package Details" in the bottom right corner. Look for and expand the `Android 14 (UpsideDownCake)` entry, then make sure the following items are checked: +Select the "SDK Platforms" tab from within the SDK Manager, then check the box next to "Show Package Details" in the bottom right corner. Look for and expand the `Android 15 (VanillaIceCream)` entry, then make sure the following items are checked: -- `Android SDK Platform 34` +- `Android SDK Platform 35` - `Intel x86 Atom_64 System Image` or `Google APIs Intel x86 Atom System Image` -Next, select the "SDK Tools" tab and check the box next to "Show Package Details" here as well. Look for and expand the `Android SDK Build-Tools` entry, then make sure that `34.0.0` is selected. +Next, select the "SDK Tools" tab and check the box next to "Show Package Details" here as well. Look for and expand the `Android SDK Build-Tools` entry, then make sure that `35.0.0` is selected. Finally, click "Apply" to download and install the Android SDK and related build tools. @@ -118,7 +118,7 @@ If you use Android Studio to open `./AwesomeProject/android`, you can see the li ![Android Studio AVD Manager](/docs/assets/GettingStartedAndroidStudioAVD.png) -If you have recently installed Android Studio, you will likely need to [create a new AVD](https://developer.android.com/studio/run/managing-avds.html). Select "Create Virtual Device...", then pick any Phone from the list and click "Next", then select the **UpsideDownCake** API Level 34 image. +If you have recently installed Android Studio, you will likely need to [create a new AVD](https://developer.android.com/studio/run/managing-avds.html). Select "Create Virtual Device...", then pick any Phone from the list and click "Next", then select the **VanillaIceCream** API Level 35 image. > If you don't have HAXM installed, click on "Install HAXM" or follow [these instructions](https://github.com/intel/haxm/wiki/Installation-Instructions-on-Windows) to set it up, then go back to the AVD Manager. diff --git a/docs/_integration-with-existing-apps-ios.md b/docs/_integration-with-existing-apps-ios.md index cd0b2df8d85..93b5b243325 100644 --- a/docs/_integration-with-existing-apps-ios.md +++ b/docs/_integration-with-existing-apps-ios.md @@ -467,10 +467,11 @@ class ViewController: UIViewController { + button.setTitleColor(.systemBlue, for: .normal) + button.setTitleColor(.blue, for: .highlighted) + button.addAction(UIAction { [weak self] _ in ++ guard let self else { return } + if reactViewController == nil { + reactViewController = ReactViewController() + } -+ self?.present(reactViewController, animated: true) ++ present(reactViewController!, animated: true) + }, for: .touchUpInside) + self.view.addSubview(button) + diff --git a/docs/_turbo-native-modules-components.jsx b/docs/_turbo-native-modules-components.jsx index 03cf1917ba9..1bb5a1b5edb 100644 --- a/docs/_turbo-native-modules-components.jsx +++ b/docs/_turbo-native-modules-components.jsx @@ -1,6 +1,6 @@ -import React from "react"; -import IOSContent from "./turbo-native-modules-ios.md"; -import AndroidContent from "./turbo-native-modules-android.md"; +import React from 'react'; +import IOSContent from './turbo-native-modules-ios.md'; +import AndroidContent from './turbo-native-modules-android.md'; export function TurboNativeModulesIOS() { return ; diff --git a/docs/accessibility.md b/docs/accessibility.md index ed452b25cc6..33e1708e43e 100644 --- a/docs/accessibility.md +++ b/docs/accessibility.md @@ -163,6 +163,26 @@ In the above example method `addOne` changes the state variable `count`. When th - **toolbar** Used to represent a toolbar (a container of action buttons or components). - **grid** Used with ScrollView, VirtualizedList, FlatList, or SectionList to represent a grid. Adds the in/out of grid announcements to Android's GridView. +### `accessibilityShowsLargeContentViewer`
iOS
+ +A boolean value that determines whether the large content viewer is shown when the user performs a long press on the element. + +Available in iOS 13.0 and later. + +### `accessibilityLargeContentTitle`
iOS
+ +A string that will be used as the title of the large content viewer when it is shown. + +Requires `accessibilityShowsLargeContentViewer` to be set to `true`. + +```tsx + + Home + +``` + ### `accessibilityState` Describes the current state of a component to the assistive technology user. @@ -340,7 +360,7 @@ In the above example, the `yellow` layout and its descendants are completely inv Assign this property to a custom function which will be called when someone performs the "escape" gesture, which is a two finger Z shaped gesture. An escape function should move back hierarchically in the user interface. This can mean moving up or back in a navigation hierarchy or dismissing a modal user interface. If the selected element does not have an `onAccessibilityEscape` function, the system will attempt to traverse up the view hierarchy until it finds a view that does or bonk to indicate it was unable to find one. -### `onAccessibilityTap` +### `onAccessibilityTap`
iOS
Use this property to assign a custom function to be called when someone activates an accessible element by double tapping on it while it's selected. @@ -363,6 +383,7 @@ Assign this property to a custom function which will be called when someone perf - **img** Used when the element should be treated as an image. Can be combined with a button or link, for example. - **link** Used when the element should be treated as a link. - **list** Used to identify a list of items. +- **listitem** Used to itentify an item in a list. - **menu** Used when the component is a menu of choices. - **menubar** Used when a component is a container of multiple menus. - **menuitem** Used to represent an item within a menu. diff --git a/docs/animated.md b/docs/animated.md index 8eee7843170..b74541b2281 100644 --- a/docs/animated.md +++ b/docs/animated.md @@ -13,14 +13,21 @@ The core workflow for creating an animation is to create an `Animated.Value`, ho The following example contains a `View` which will fade in and fade out based on the animated value `fadeAnim` -```SnackPlayer name=Animated%20Example -import React, {useRef} from 'react'; -import {Animated, Text, View, StyleSheet, Button} from 'react-native'; +```SnackPlayer name=Animated%20Example&supportedPlatforms=ios,android +import React from 'react'; import {SafeAreaView, SafeAreaProvider} from 'react-native-safe-area-context'; +import { + Animated, + Text, + View, + StyleSheet, + Button, + useAnimatedValue, +} from 'react-native'; const App = () => { // fadeAnim will be used as the value for opacity. Initial Value: 0 - const fadeAnim = useRef(new Animated.Value(0)).current; + const fadeAnim = useAnimatedValue(0); const fadeIn = () => { // Will change fadeAnim value to 1 in 5 seconds @@ -495,7 +502,7 @@ Stops any running animation and resets the value to its original. ### `Value` -Standard value class for driving animations. Typically initialized with `new Animated.Value(0);` +Standard value class for driving animations. Typically initialized with `useAnimatedValue(0);` or `new Animated.Value(0);` in class components. You can read more about `Animated.Value` API on the separate [page](animatedvalue). diff --git a/docs/animatedvalue.md b/docs/animatedvalue.md index f6caa7ba422..189df398ec0 100644 --- a/docs/animatedvalue.md +++ b/docs/animatedvalue.md @@ -5,7 +5,7 @@ title: Animated.Value Standard value for driving animations. One `Animated.Value` can drive multiple properties in a synchronized fashion, but can only be driven by one mechanism at a time. Using a new mechanism (e.g. starting a new animation, or calling `setValue`) will stop any previous ones. -Typically initialized with `new Animated.Value(0);` +Typically initialized with `useAnimatedValue(0);` or `new Animated.Value(0);` in class components. --- diff --git a/docs/animations.md b/docs/animations.md index cd298a9164b..d07e9c7bf8f 100644 --- a/docs/animations.md +++ b/docs/animations.md @@ -20,12 +20,12 @@ For example, a container view that fades in when it is mounted may look like thi -```SnackPlayer ext=js -import React, {useRef, useEffect} from 'react'; -import {Animated, Text, View} from 'react-native'; +```SnackPlayer ext=js&supportedPlatforms=ios,android +import React, {useEffect} from 'react'; +import {Animated, Text, View, useAnimatedValue} from 'react-native'; const FadeInView = props => { - const fadeAnim = useRef(new Animated.Value(0)).current; // Initial value for opacity: 0 + const fadeAnim = useAnimatedValue(0); // Initial value for opacity: 0 useEffect(() => { Animated.timing(fadeAnim, { @@ -74,15 +74,15 @@ export default () => { ```SnackPlayer ext=tsx -import React, {useRef, useEffect} from 'react'; -import {Animated, Text, View} from 'react-native'; +import React, {useEffect} from 'react'; +import {Animated, Text, View, useAnimatedValue} from 'react-native'; import type {PropsWithChildren} from 'react'; import type {ViewStyle} from 'react-native'; type FadeInViewProps = PropsWithChildren<{style: ViewStyle}>; const FadeInView: React.FC = props => { - const fadeAnim = useRef(new Animated.Value(0)).current; // Initial value for opacity: 0 + const fadeAnim = useAnimatedValue(0); // Initial value for opacity: 0 useEffect(() => { Animated.timing(fadeAnim, { @@ -130,7 +130,7 @@ export default () => { -Let's break down what's happening here. In the `FadeInView` constructor, a new `Animated.Value` called `fadeAnim` is initialized as part of `state`. The opacity property on the `View` is mapped to this animated value. Behind the scenes, the numeric value is extracted and used to set opacity. +Let's break down what's happening here. In the `FadeInView` render method, a new `Animated.Value` called `fadeAnim` is initialized with `useRef`. The opacity property on the `View` is mapped to this animated value. Behind the scenes, the numeric value is extracted and used to set opacity. When the component mounts, the opacity is set to 0. Then, an easing animation is started on the `fadeAnim` animated value, which will update all of its dependent mappings (in this case, only the opacity) on each frame as the value animates to the final value of 1. @@ -281,8 +281,8 @@ Animated.timing(opacity, { toValue: pan.x.interpolate({ inputRange: [0, 300], outputRange: [1, 0], - useNativeDriver: true, }), + useNativeDriver: true, }).start(); ``` @@ -311,7 +311,7 @@ The following example implements a horizontal scrolling carousel where the scrol #### ScrollView with Animated Event Example ```SnackPlayer name=Animated&supportedPlatforms=ios,android -import React, {useRef} from 'react'; +import React from 'react'; import { ScrollView, Text, @@ -320,6 +320,7 @@ import { ImageBackground, Animated, useWindowDimensions, + useAnimatedValue, } from 'react-native'; import {SafeAreaView, SafeAreaProvider} from 'react-native-safe-area-context'; @@ -328,7 +329,7 @@ const images = new Array(6).fill( ); const App = () => { - const scrollX = useRef(new Animated.Value(0)).current; + const scrollX = useAnimatedValue(0); const {width: windowWidth} = useWindowDimensions(); diff --git a/docs/debugging.md b/docs/debugging.md index f82119c5e5b..c264a850e0d 100644 --- a/docs/debugging.md +++ b/docs/debugging.md @@ -9,7 +9,7 @@ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; import con React Native provides an in-app developer menu which offers several debugging options. You can access the Dev Menu by shaking your device or via keyboard shortcuts: -- iOS Simulator: Cmd ⌘ + D (or Device > Shake) +- iOS Simulator: Ctrl + Cmd ⌘ + Z (or Device > Shake) - Android emulators: Cmd ⌘ + M (macOS) or Ctrl + M (Windows and Linux) Alternatively for Android devices and emulators, you can run `adb shell input keyevent 82` in your terminal. @@ -49,7 +49,7 @@ React Native DevTools replaces the previous Flipper, Experimental Debugger, and We continue to offer legacy debugging methods such as Direct JSC Debugging and Remote JS Debugging (deprecated) (see [Other Debugging Methods](./other-debugging-methods)). -React Native DevTools is designed for debugging React app concerns, and not to replace native tools. If you want to inspect React Native’s underlying platform layers (for example, while developing a Native Module), please use the debugging tools available in Xcode and Android Studio (see [Debugging Native Code](http://localhost:3000/docs/next/debugging-native-code)). +React Native DevTools is designed for debugging React app concerns, and not to replace native tools. If you want to inspect React Native’s underlying platform layers (for example, while developing a Native Module), please use the debugging tools available in Xcode and Android Studio (see [Debugging Native Code](/docs/next/debugging-native-code)). Other useful links: diff --git a/docs/easing.md b/docs/easing.md index 25eda066740..712595b4bac 100644 --- a/docs/easing.md +++ b/docs/easing.md @@ -48,7 +48,7 @@ The following helpers are used to modify other easing functions. -```SnackPlayer name=Easing%20Demo&ext=js +```SnackPlayer name=Easing%20Demo&ext=js&supportedPlatforms=ios,android import React from 'react'; import { Animated, @@ -59,11 +59,12 @@ import { Text, TouchableOpacity, View, + useAnimatedValue, } from 'react-native'; import {SafeAreaView, SafeAreaProvider} from 'react-native-safe-area-context'; const App = () => { - let opacity = new Animated.Value(0); + const opacity = useAnimatedValue(0); const animate = easing => { opacity.setValue(0); @@ -219,12 +220,13 @@ import { Text, TouchableOpacity, View, + useAnimatedValue, type EasingFunction, } from 'react-native'; import {SafeAreaView, SafeAreaProvider} from 'react-native-safe-area-context'; const App = () => { - let opacity = new Animated.Value(0); + const opacity = useAnimatedValue(0); const animate = (easing: EasingFunction) => { opacity.setValue(0); diff --git a/docs/fabric-native-components-android.md b/docs/fabric-native-components-android.md index 9b51fddcfa7..f9eb3730007 100644 --- a/docs/fabric-native-components-android.md +++ b/docs/fabric-native-components-android.md @@ -163,9 +163,9 @@ class ReactWebView: WebView { eventDispatcher?.dispatchEvent(event) } - enum class OnScriptLoadedEventResult() { - success(), - error() + enum class OnScriptLoadedEventResult { + success, + error; } inner class OnScriptLoadedEvent( @@ -199,7 +199,7 @@ The code then defines a helper function to actually emit an event. To emit an ev The last part of the file contains the definition of the data types you need to send the event: - The `OnScriptLoadedEventResult`, with the possible outcomes of the `OnScriptLoaded` event. -- The actual ``OnScriptLoadedEvent` that needs to extend the React Native's `Event` class. +- The actual `OnScriptLoadedEvent` that needs to extend the React Native's `Event` class. ### 3. Write the `WebViewManager` @@ -351,7 +351,7 @@ This is the code for the `ReactWebViewPackage`: ```java title="Demo/android/src/main/java/com/webview/ReactWebViewPackage.java" package com.webview; -import com.facebook.react.TurboReactPackage; +import com.facebook.react.BaseReactPackage; import com.facebook.react.bridge.NativeModule; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.module.model.ReactModuleInfo; @@ -363,7 +363,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -public class ReactWebViewPackage extends TurboReactPackage { +public class ReactWebViewPackage extends BaseReactPackage { @Override public List> createViewManagers(ReactApplicationContext reactContext) { return Collections.singletonList(new ReactWebViewManager(reactContext)); @@ -404,14 +404,14 @@ public class ReactWebViewPackage extends TurboReactPackage { ```kotlin title="Demo/android/src/main/java/com/webview/ReactWebView.kt" package com.webview -import com.facebook.react.TurboReactPackage +import com.facebook.react.BaseReactPackage import com.facebook.react.bridge.NativeModule import com.facebook.react.bridge.ReactApplicationContext import com.facebook.react.module.model.ReactModuleInfo import com.facebook.react.module.model.ReactModuleInfoProvider import com.facebook.react.uimanager.ViewManager -class ReactWebViewPackage : TurboReactPackage() { +class ReactWebViewPackage : BaseReactPackage() { override fun createViewManagers(reactContext: ReactApplicationContext): List> { return listOf(ReactWebViewManager(reactContext)) } @@ -440,7 +440,7 @@ class ReactWebViewPackage : TurboReactPackage() { -The `ReactWebViewPackage` extends the `TurboReactPackage` and implements all the methods required to properly register our component. +The `ReactWebViewPackage` extends the `BaseReactPackage` and implements all the methods required to properly register our component. - the `createViewManagers` method is the factory method that creates the `ViewManager` that manage the custom views. - the `getModule` method returns the proper ViewManager depending on the View that React Native needs to render. diff --git a/docs/fabric-native-components-ios.md b/docs/fabric-native-components-ios.md index b8a8c6dd07d..879e2a20f9d 100644 --- a/docs/fabric-native-components-ios.md +++ b/docs/fabric-native-components-ios.md @@ -52,7 +52,9 @@ open Demo.xcworkspace Create an Objective-C RCTWebView class -5. Rename RCTWebView.mRCTWebView.mm making it an Objective-C++ file +5. Repeat step 4 and create a header file named `RCTWebView.h`. + +6. Rename RCTWebView.mRCTWebView.mm making it an Objective-C++ file. ```text title="Demo/ios" Podfile @@ -72,7 +74,7 @@ After creating the header file and the implementation file, you can start implem This is the code for the `RCTWebView.h` file, which declares the component interface. -```objc title="Demo/RCTWebView/RTNWebView.h" +```objc title="Demo/RCTWebView/RCTWebView.h" #import #import @@ -94,10 +96,10 @@ The code for the implementation file (`RCTWebView.mm`) is the following: ```objc title="Demo/RCTWebView/RCTWebView.mm" #import "RCTWebView.h" -#import -#import -#import -#import +#import +#import +#import +#import // highlight-next-line #import @@ -181,11 +183,6 @@ using namespace facebook::react; return concreteComponentDescriptorProvider(); } -Class WebViewCls(void) -{ - return RCTWebView.class; -} - @end ``` @@ -201,40 +198,30 @@ This code is written in Objective-C++ and contains various details: - the `urlIsValid:(std::string)propString` method that checks whether the URL received as prop is valid; - the `eventEmitter` method which is a utility to retrieve a strongly typed `eventEmitter` instance - the `componentDescriptorProvider` which returns the `ComponentDescriptor` generated by Codegen; -- the `WebViewCls` which is an helper method to register the `RCTWebView` in the application. -#### AppDelegate.mm +#### Add WebKit framework -Finally, you can register the component in the app. -Update the `AppDelegate.mm` to make your application aware of our custom WebView component: +:::note +This step is only required because we are creating a Web view. Web components on iOS needs to be linked againt the WebKit framework provided by Apple. If your component doesn't need to access web-specific features, you can skip this step. +::: -```objc title="Demo/ios/Demo/AppDelegate.mm" -#import "AppDelegate.h" +A web view requires access to some features that Apple provides through one of the frameworks shipped with Xcode and the devices: WebKit. +You can see it in the native code by the `#import ` line added in the `RCTWebView.mm`. -#import -// highlight-start -#import -#import "RCTWebView.h" -// highlight-end -@implementation AppDelegate -// ... -// highlight-start -- (NSDictionary> *)thirdPartyFabricComponents -{ - NSMutableDictionary * dictionary = [super thirdPartyFabricComponents].mutableCopy; - dictionary[@"CustomWebView"] = [RCTWebView class]; - return dictionary; -} -// highlight-end +To link the WebKit framework in your app, follow these steps: -@end -``` +1. In Xcode, Click on your project +2. Select the app target +3. Select the General tab +4. Scroll down until you find the _"Frameworks, Libraries, and Embedded Contents"_ section, and press the `+` button -This code overrides the `thirdPartyFabricComponents` method by obtaining a mutable copy of the dictionary of third party components coming from other sources, like third party libraries. +Add webkit framework to your app 1 -It then adds an entry to the dictionary with the name used in the Codegen specification file. In this way, when React is required to load a component with name `CustomWebView`, React Native will instantiate a `RCTWebView`. +5. In the search bar, filter for WebKit +6. Select the WebKit framework +7. Click on Add. -Finally, it returns the new dictionary. +Add webkit framework to your app 2 :::warning We are aware of a couple of issues with iOS that would create some problem when building the app with a custom iOS component. @@ -242,5 +229,5 @@ We are aware of a couple of issues with iOS that would create some problem when 1. The component requires access to the `yoga/style/Style.h` header which is not currently available for the application. To fix this, add the `$(PODS_ROOT)/Headers/Private/Yoga` path to the header search paths build settings of the app. 2. Codegen is generating a line in the `RCTThirdPartyFabricComponentsProvider` that it should not generate. Remove the lines with the `WebViewCls` symbol in the `RCTThirdPartyFabricComponentsProvider.h` and `RCTThirdPartyFabricComponentsProvider.mm` files. -We have already fixed those issues and they will be released in React Native 0.76.1 +We have already fixed those issues and they will be released in React Native 0.76.2. ::: diff --git a/docs/fabric-native-components.md b/docs/fabric-native-components.md index cc55cbe83a4..286bbc8b254 100644 --- a/docs/fabric-native-components.md +++ b/docs/fabric-native-components.md @@ -41,12 +41,12 @@ This gives you the following layout where you'll working: Demo ├── android/app/src/main/java/com/webview └── ios -└── spec +└── specs ``` - The `android/app/src/main/java/com/webview` folder is the folder that will contain our Android code. - The `ios` folder is the folder that will contain our iOS code. -- The `spec` folder is the folder that will contain the Codegen's specification file. +- The `specs` folder is the folder that will contain the Codegen's specification file. ## 1. Define Specification for Codegen @@ -107,11 +107,11 @@ export default (codegenNativeComponent( -This specification is composed of three main parts, exluding the imports: +This specification is composed of three main parts, excluding the imports: - The `WebViewScriptLoadedEvent` is a supporting data type for the data the event needs to pass from native to JavaScript. -- The `NativeProps` which is a definition of the props that we can set on the component. -- The `codegenNativeComponent` statement that allows us to codegenerate the code for the custom component and that defines a name for the component used to match the native implementations. +- The `NativeProps` is a definition of the props that we can set on the component. +- The `codegenNativeComponent` statement allows us to codegenerate the code for the custom component and that defines a name for the component used to match the native implementations. As with Native Modules, you can have multiple specification files in the `specs/` directory. For more information about the types you can use, and the platform types these map to, see the [appendix](appendix.md#codegen-typings). @@ -120,27 +120,34 @@ As with Native Modules, you can have multiple specification files in the `specs/ The specification is used by the React Native's Codegen tools to generate platform specific interfaces and boilerplate for us. To do this, Codegen needs to know where to find our specification and what to do with it. Update your `package.json` to include: ```json package.json - "start": "react-native start", - "test": "jest" - }, - // highlight-start - "codegenConfig": { - "name": "AppSpec", - "type": "components", - "jsSrcsDir": "specs", - "android": { - "javaPackageName": "com.webview" - } - }, - // highlight-end - "dependencies": { + "start": "react-native start", + "test": "jest" + }, + // highlight-start + "codegenConfig": { + "name": "AppSpec", + "type": "components", + "jsSrcsDir": "specs", + "android": { + "javaPackageName": "com.webview" + }, + "ios": { + "componentProvider": { + "CustomWebView": "RCTWebView" + } + } + }, + // highlight-end + "dependencies": { ``` With everything wired up for Codegen, we need to prepare our native code to hook into our generated code. +Note that for iOS, we are declaratively mapping the name of the JS component that is exported by the spec (`CustomWebView`) with the iOS class that will implement the component natively. + ## 2. Building your Native Code -Now it's time to write the native platform code so that when React requires to render a view, te platform can create the right native view and can render it on screen. +Now it's time to write the native platform code so that when React requires to render a view, the platform can create the right native view and can render it on screen. You should work through both the Android and iOS platforms. @@ -200,7 +207,7 @@ This code creates an app that uses the new `WebView` component we created to loa The app also shows an alert when the web page is loaded. -## 5. Run your App using the WebView Component +## 4. Run your App using the WebView Component diff --git a/docs/handling-text-input.md b/docs/handling-text-input.md index 532f051c799..4b5225725fb 100644 --- a/docs/handling-text-input.md +++ b/docs/handling-text-input.md @@ -16,7 +16,7 @@ const PizzaTranslator = () => { return ( setText(newText)} defaultValue={text} diff --git a/docs/image.md b/docs/image.md index 7e726dd4ece..9511a751ed2 100644 --- a/docs/image.md +++ b/docs/image.md @@ -100,14 +100,14 @@ dependencies { implementation 'com.facebook.fresco:animated-base-support:1.3.0' // For animated GIF support - implementation 'com.facebook.fresco:animated-gif:3.1.3' + implementation 'com.facebook.fresco:animated-gif:3.2.0' // For WebP support, including animated WebP - implementation 'com.facebook.fresco:animated-webp:3.1.3' - implementation 'com.facebook.fresco:webpsupport:3.1.3' + implementation 'com.facebook.fresco:animated-webp:3.2.0' + implementation 'com.facebook.fresco:webpsupport:3.2.0' // For WebP support, without animations - implementation 'com.facebook.fresco:webpsupport:3.1.3' + implementation 'com.facebook.fresco:webpsupport:3.2.0' } ``` @@ -387,7 +387,7 @@ If you have a source image with dimensions 200x200 and destination dimensions of The image source (either a remote URL or a local file resource). -This prop can also contain several remote URLs, specified together with their width and height and potentially with scale/other URI arguments. The native side will then choose the best `uri` to display based on the measured size of the image container. A `cache` property can be added to control how networked request interacts with the local cache. (For more information see [Cache Control for Images](images#cache-control-ios-only)). +This prop can also contain several remote URLs, specified together with their width and height and potentially with scale/other URI arguments. The native side will then choose the best `uri` to display based on the measured size of the image container. A `cache` property can be added to control how networked request interacts with the local cache. (For more information see [Cache Control for Images](images#cache-control)). The currently supported formats are `png`, `jpg`, `jpeg`, `bmp`, `gif`, `webp`, `psd` (iOS only). In addition, iOS supports several RAW image formats. Refer to Apple's documentation for the current list of supported camera models (for iOS 12, see https://support.apple.com/en-ca/HT208967). @@ -484,11 +484,7 @@ Abort prefetch request. ### `getSize()` ```tsx -static getSize( - uri: string, - success: (width: number, height: number) => void, - failure?: (error: any) => void, -): any; +static getSize(uri: string): Promise<{width: number, height: number}>; ``` Retrieve the width and height (in pixels) of an image prior to displaying it. This method can fail if the image cannot be found, or fails to download. @@ -497,11 +493,9 @@ In order to retrieve the image dimensions, the image may first need to be loaded **Parameters:** -|
Name
| Type | Description | -| -------------------------------------------------------- | -------- | ---------------------------------------------------------------------------------------------------- | -| uri
Required
| string | The location of the image. | -| success
Required
| function | The function that will be called if the image was successfully found and width and height retrieved. | -| failure | function | The function that will be called if there was an error, such as failing to retrieve the image. | +|
Name
| Type | Description | +| ---------------------------------------------------- | ------ | -------------------------- | +| uri
Required
| string | The location of the image. | --- @@ -510,10 +504,8 @@ In order to retrieve the image dimensions, the image may first need to be loaded ```tsx static getSizeWithHeaders( uri: string, - headers: {[index: string]: string}, - success: (width: number, height: number) => void, - failure?: (error: any) => void, -): any; + headers: {[index: string]: string} +): Promise<{width: number, height: number}>; ``` Retrieve the width and height (in pixels) of an image prior to displaying it with the ability to provide the headers for the request. This method can fail if the image cannot be found, or fails to download. It also does not work for static image resources. @@ -522,12 +514,10 @@ In order to retrieve the image dimensions, the image may first need to be loaded **Parameters:** -|
Name
| Type | Description | -| -------------------------------------------------------- | -------- | ---------------------------------------------------------------------------------------------------- | -| uri
Required
| string | The location of the image. | -| headers
Required
| object | The headers for the request. | -| success
Required
| function | The function that will be called if the image was successfully found and width and height retrieved. | -| failure | function | The function that will be called if there was an error, such as failing to retrieve the image. | +|
Name
| Type | Description | +| -------------------------------------------------------- | ------ | ---------------------------- | +| uri
Required
| string | The location of the image. | +| headers
Required
| object | The headers for the request. | --- diff --git a/docs/images.md b/docs/images.md index 1afecdecdb7..dfdf182c145 100644 --- a/docs/images.md +++ b/docs/images.md @@ -150,7 +150,7 @@ This is recommended for very small and dynamic images only, like icons in a list /> ``` -### Cache Control (iOS Only) +### Cache Control In some cases you might only want to display an image if it is already in the local cache, i.e. a low resolution placeholder until a higher resolution is available. In other cases you do not care if the image is outdated and are willing to display an outdated image to save bandwidth. The `cache` source property gives you control over how the network layer interacts with the cache. diff --git a/docs/interactionmanager.md b/docs/interactionmanager.md index d0916603260..f9265e7db16 100644 --- a/docs/interactionmanager.md +++ b/docs/interactionmanager.md @@ -47,7 +47,7 @@ By default, queued tasks are executed together in a loop in one `setImmediate` b ```SnackPlayer name=InteractionManager%20Function%20Component%20Basic%20Example&supportedPlatforms=ios,android&ext=js -import React, {useState, useEffect} from 'react'; +import React, {useEffect} from 'react'; import { Alert, Animated, @@ -55,6 +55,7 @@ import { Platform, StyleSheet, Text, + useAnimatedValue, } from 'react-native'; import {SafeAreaView, SafeAreaProvider} from 'react-native-safe-area-context'; @@ -66,7 +67,7 @@ const instructions = Platform.select({ }); const useFadeIn = (duration = 5000) => { - const [opacity] = useState(new Animated.Value(0)); + const opacity = useAnimatedValue(0); // Running the animation when the component is mounted useEffect(() => { @@ -128,7 +129,7 @@ export default App; ```SnackPlayer name=InteractionManager%20Function%20Component%20Basic%20Example&supportedPlatforms=ios,android&ext=tsx -import React, {useState, useEffect} from 'react'; +import React, {useEffect} from 'react'; import { Alert, Animated, @@ -136,6 +137,7 @@ import { Platform, StyleSheet, Text, + useAnimatedValue, } from 'react-native'; import {SafeAreaView, SafeAreaProvider} from 'react-native-safe-area-context'; @@ -147,7 +149,7 @@ const instructions = Platform.select({ }); const useFadeIn = (duration = 5000) => { - const [opacity] = useState(new Animated.Value(0)); + const opacity = useAnimatedValue(0); // Running the animation when the component is mounted useEffect(() => { diff --git a/docs/legacy/direct-manipulation.md b/docs/legacy/direct-manipulation.md index 1b05aeadd7c..f4a9ef83e6e 100644 --- a/docs/legacy/direct-manipulation.md +++ b/docs/legacy/direct-manipulation.md @@ -313,7 +313,7 @@ Determines the location of the given view in the window and returns the values v Like `measure()`, but measures the view relative to an ancestor, specified with `relativeToNativeComponentRef` reference. This means that the returned coordinates are relative to the origin `x`, `y` of the ancestor view. :::note -This method can also be called with a `relativeToNativeNode` handler (instead of reference), but this variant is deprecated. +This method can also be called with a `relativeToNativeNode` handler (instead of reference), but this variant is obsolete with the new architecture. ::: diff --git a/docs/other-debugging-methods.md b/docs/other-debugging-methods.md index 88c7289f8e4..2e1e89a9131 100644 --- a/docs/other-debugging-methods.md +++ b/docs/other-debugging-methods.md @@ -64,7 +64,7 @@ Under Remote JavaScript Debugging, the web version of React DevTools in Chrome w ::: :::note -On Android, if the times between the debugger and device have drifted, things such as animations and event behavior might not work properly. This can be fixed by running `` adb shell "date `date +%m%d%H%M%Y.%S%3N`" ``. Root access is required if using a physical device. +On Android, if the times between the debugger and device have drifted, things such as animations and event behavior might not work properly. This can be fixed by running ``adb shell "date `date +%m%d%H%M%Y.%S%3N`"``. Root access is required if using a physical device. ::: ### Debugging on a physical device diff --git a/docs/profiling.md b/docs/profiling.md index 440670cee89..bd19ffa1aec 100644 --- a/docs/profiling.md +++ b/docs/profiling.md @@ -5,37 +5,27 @@ title: Profiling Profiling is the process of analyzing an app's performance, resource usage, and behavior to identify potential bottlenecks or inefficiencies. It's worth making use of profiling tools to ensure your app works smoothly across different devices and conditions. -For iOS, Instruments is an invaluable tool, and on Android you should learn to use [`systrace`](profiling.md#profiling-android-ui-performance-with-systrace). +For iOS, Instruments is an invaluable tool, and on Android you should learn to use the [Android Studio Profiler](profiling.md#profiling-android-ui-performance-with-system-tracing). But first, [**make sure that Development Mode is OFF!**](performance.md#running-in-development-mode-devtrue) You should see `__DEV__ === false, development-level warning are OFF, performance optimizations are ON` in your application logs. -## Profiling Android UI Performance with `systrace` +## Profiling Android UI Performance with System Tracing Android supports 10k+ different phones and is generalized to support software rendering: the framework architecture and need to generalize across many hardware targets unfortunately means you get less for free relative to iOS. But sometimes, there are things you can improve -- and many times it's not native code's fault at all! -The first step for debugging this jank is to answer the fundamental question of where your time is being spent during each 16ms frame. For that, we'll be using a standard Android profiling tool called `systrace`. - -`systrace` is a standard Android marker-based profiling tool (and is installed when you install the Android platform-tools package). Profiled code blocks are surrounded by start/end markers which are then visualized in a colorful chart format. Both the Android SDK and React Native framework provide standard markers that you can visualize. +The first step for debugging this jank is to answer the fundamental question of where your time is being spent during each 16ms frame. For that, we'll be using the [built-in System Tracing profiler in the Android Studio](https://developer.android.com/studio/profile). ### 1. Collecting a trace -First, connect a device that exhibits the stuttering you want to investigate to your computer via USB and get it to the point right before the navigation/animation you want to profile. Run `systrace` as follows: - -```shell -$ /platform-tools/systrace/systrace.py --time=10 -o trace.html sched gfx view -a -``` +First, connect a device that exhibits the stuttering you want to investigate to your computer via USB. Open your project's `android` folder in Android Studio, select your device in the top right pane, and [run your project as profileable](https://developer.android.com/studio/profile#build-and-run). -A quick breakdown of this command: +When your app is built as profileable and is running on the device, get your app to the point right before the navigation/animation you want to profile and start the ["Capture System Activities" task](https://developer.android.com/studio/profile#start-profiling) in the Android Studio Profiler pane. -- `time` is the length of time the trace will be collected in seconds -- `sched`, `gfx`, and `view` are the android SDK tags (collections of markers) we care about: `sched` gives you information about what's running on each core of your phone, `gfx` gives you graphics info such as frame boundaries, and `view` gives you information about measure, layout, and draw passes -- `-a ` enables app-specific markers, specifically the ones built into the React Native framework. `your_package_name` can be found in the `AndroidManifest.xml` of your app and looks like `com.example.app` - -Once the trace starts collecting, perform the animation or interaction you care about. At the end of the trace, systrace will give you a link to the trace which you can open in your browser. +Once the trace starts collecting, perform the animation or interaction you care about. Then press "Stop recording". You can now [inspect the trace directly in the Android Studio](https://developer.android.com/studio/profile/jank-detection). Alternatively, you can select it in the "Past Recordings" pane, press "Export recording", and open it in a tool like [Perfetto](https://perfetto.dev/). ### 2. Reading the trace -After opening the trace in your browser (preferably Chrome), you should see something like this: +After opening the trace in Android Studio or Perfetto, you should see something like this: ![Example](/docs/assets/SystraceExample.png) @@ -43,15 +33,7 @@ After opening the trace in your browser (preferably Chrome), you should see some Use the WASD keys to strafe and zoom. ::: -If your trace .html file isn't opening correctly, check your browser console for the following: - -![ObjectObserveError](/docs/assets/ObjectObserveError.png) - -Since `Object.observe` was deprecated in recent browsers, you may have to open the file from the Google Chrome Tracing tool. You can do so by: - -- Opening tab in chrome chrome://tracing -- Selecting load -- Selecting the html file generated from the previous command. +The exact UI might be different but the instructions below will apply regardless of the tool you're using. :::info Enable VSync highlighting Check this checkbox at the top right of the screen to highlight the 16ms frame boundaries: @@ -142,3 +124,16 @@ In the second scenario, you'll see something more like this: Notice that first the JS thread thinks for a bit, then you see some work done on the native modules thread, followed by an expensive traversal on the UI thread. There isn't a quick way to mitigate this unless you're able to postpone creating new UI until after the interaction, or you are able to simplify the UI you're creating. The react native team is working on an infrastructure level solution for this that will allow new UI to be created and configured off the main thread, allowing the interaction to continue smoothly. + +### Finding native CPU hotspots + +If the problem seems to be on the native side, you can use the [CPU hotspot profiler](https://developer.android.com/studio/profile/record-java-kotlin-methods) to get more details on what's happening. Open the Android Studio Profiler panel and select "Find CPU Hotspots (Java/Kotlin Method Recording)". + +:::info Choose the Java/Kotlin recording + +Make sure you select "Find CPU Hotspots **(Java/Kotlin Recording)**" rather than "Find CPU Hotspots (Callstack Sample)". They have similar icons but do different things. +::: + +Perform the interactions and press "Stop recording". Recording is resource-intensive, so keep the interaction short. You can then either inspect the resulting trace in the Android Studio or export it and open it in an online tool like [Firefox Profiler](https://profiler.firefox.com/). + +Unlike System Trace, CPU hotspot profiling is slow so it won't give you accurate measurements. However, it should give you an idea of what native methods are being called, and where the time is being spent proportionally during each frame. diff --git a/docs/sectionlist.md b/docs/sectionlist.md index c5bd932bf7a..0c0dbd2bd1c 100644 --- a/docs/sectionlist.md +++ b/docs/sectionlist.md @@ -179,7 +179,7 @@ Rendered in between each item, but not at the top or bottom. By default, `highli ### `keyExtractor` -Used to extract a unique key for a given item at the specified index. Key is used for caching and as the React key to track item re-ordering. The default extractor checks `item.key`, then falls back to using the index, like React does. Note that this sets keys for each item, but each overall section still needs its own key. +Used to extract a unique key for a given item at the specified index. Key is used for caching and as the React key to track item re-ordering. The default extractor checks `item.key`, then `item.id`, and then falls back to using the index, like React does. Note that this sets keys for each item, but each overall section still needs its own key. | Type | | --------------------------------------- | diff --git a/docs/textinput.md b/docs/textinput.md index 4127fccd83e..158ce9691de 100644 --- a/docs/textinput.md +++ b/docs/textinput.md @@ -231,7 +231,7 @@ If `false`, disables auto-correct. The default value is `true`. ### `autoFocus` -If `true`, focuses the input on `componentDidMount` or `useEffect`. The default value is `false`. +If `true`, focuses the input. The default value is `false`. | Type | | ---- | @@ -241,6 +241,8 @@ If `true`, focuses the input on `componentDidMount` or `useEffect`. The default ### `blurOnSubmit` +> **Deprecated.** Note that `submitBehavior` now takes the place of `blurOnSubmit` and will override any behavior defined by `blurOnSubmit`. See [submitBehavior](textinput#submitbehavior) + If `true`, the text field will blur when submitted. The default value is true for single-line fields and false for multiline fields. Note that for multiline fields, setting `blurOnSubmit` to `true` means that pressing return will blur the field and trigger the `onSubmitEditing` event instead of inserting a newline into the field. | Type | @@ -865,6 +867,31 @@ If `false`, disables spell-check style (i.e. red underlines). The default value --- +### `submitBehavior` + +When the return key is pressed, + +For single line inputs: + +- `'newline'` defaults to `'blurAndSubmit'` +- `undefined` defaults to `'blurAndSubmit'` + +For multiline inputs: + +- `'newline'` adds a newline +- `undefined` defaults to `'newline'` + +For both single line and multiline inputs: + +- `'submit'` will only send a submit event and not blur the input +- `'blurAndSubmit`' will both blur the input and send a submit event + +| Type | +| ------------------------------------------ | +| enum('submit', 'blurAndSubmit', 'newline') | + +--- + ### `textAlign` Align the input text to the left, center, or right sides of the input field. diff --git a/docs/the-new-architecture/codegen-cli.md b/docs/the-new-architecture/codegen-cli.md index d1f22a45d2e..e06d23c67d6 100644 --- a/docs/the-new-architecture/codegen-cli.md +++ b/docs/the-new-architecture/codegen-cli.md @@ -2,7 +2,7 @@ Calling Gradle or manually calling a script might be hard to remember and it requires a lot of ceremony. -To simplify it, we created a CLI tool that can help you running those tasks: the **Codegen** cli. This command runs [react-native-codegen](https://www.npmjs.com/package/react-native-codegen) for your project. The following options are available: +To simplify it, we created a CLI tool that can help you running those tasks: the **Codegen** cli. This command runs [@react-native/codegen](https://www.npmjs.com/package/@react-native/codegen) for your project. The following options are available: ```sh npx @react-native-community/cli codegen --help @@ -21,19 +21,19 @@ Options: - Read `package.json` from the current working directory, generate code based on its codegenConfig. ```shell -npx @react-native-codegen/cli codegen +npx @react-native-community/cli codegen ``` - Read `package.json` from the current working directory, generate iOS code in the location defined in the codegenConfig. ```shell -npx @react-native-codegen/cli codegen --platform ios +npx @react-native-community/cli codegen --platform ios ``` - Read `package.json` from `third-party/some-library`, generate Android code in `third-party/some-library/android/generated`. ```shell -npx @react-native-codegen/cli codegen \ +npx @react-native-community/cli codegen \ --path third-party/some-library \ --platform android \ --outputPath third-party/some-library/android/generated diff --git a/docs/the-new-architecture/layout-measurements.md b/docs/the-new-architecture/layout-measurements.md index 2036d8eb96f..46b720263cf 100644 --- a/docs/the-new-architecture/layout-measurements.md +++ b/docs/the-new-architecture/layout-measurements.md @@ -13,8 +13,8 @@ function AComponent(children) { const targetRef = React.useRef(null) useLayoutEffect(() => { - targetRef.current?.measure(({measurements}) => { - //do something with the `measurements` + targetRef.current?.measure((x, y, width, height, pageX, pageY) => { + //do something with the measurements }); }, [ /* add dependencies here */]); diff --git a/docs/the-new-architecture/using-codegen.md b/docs/the-new-architecture/using-codegen.md index 9329898754e..e51aaed3b78 100644 --- a/docs/the-new-architecture/using-codegen.md +++ b/docs/the-new-architecture/using-codegen.md @@ -50,8 +50,8 @@ You can add this snippet to your app and customize the various fields: When **Codegen** runs, it searches among all the dependencies of the app, looking for JS files that respects some specific conventions, and it generates the required code: -- Turbo Native Modules requires that the spec files are prefixed with `Native`. For example, `NativeLocalStorage.ts` is a valid name for a spec file. -- Native Fabric Components requires that the spec files are suffixed with `NativeComponent`. For example, `WebViewNativeComponent.ts` is a valid name for a spec file. +- Turbo Native Modules require that the spec files are prefixed with `Native`. For example, `NativeLocalStorage.ts` is a valid name for a spec file. +- Native Fabric Components require that the spec files are suffixed with `NativeComponent`. For example, `WebViewNativeComponent.ts` is a valid name for a spec file. ## Running **Codegen** @@ -65,7 +65,7 @@ The rest of this guide assumes that you have a Native Turbo Module, a Native Fab ./gradlew generateCodegenArtifactsFromSchema ``` -This task invokes the `generateCodegenArtifactsFromSchema` command on all the the imported projects of the app (the app and all the node modules which are linked to it). It generates the code in the corresponding `node_modules/` folder. For example, if you have a Fabric Native Component whose Node module is called `my-fabric-component`, the generated code is located in the `SampleApp/node_modules/my-fabric-component/android/build/generated/source/codegen` path. For the app, the code is generated in the `android/app/build/generated/source/codegen` folder. +This task invokes the `generateCodegenArtifactsFromSchema` command on all the imported projects of the app (the app and all the node modules which are linked to it). It generates the code in the corresponding `node_modules/` folder. For example, if you have a Fabric Native Component whose Node module is called `my-fabric-component`, the generated code is located in the `SampleApp/node_modules/my-fabric-component/android/build/generated/source/codegen` path. For the app, the code is generated in the `android/app/build/generated/source/codegen` folder. #### The Generated Code @@ -111,14 +111,14 @@ build The generated code is split in two folders: - `java` which contains the platform specific code -- `jni` which contains the C++ code required to let JS and Java interac correctly. +- `jni` which contains the C++ code required to let JS and Java interact correctly. In the `java` folder, you can find the Fabric Native component generated code in the `com/facebook/viewmanagers` subfolder. - the `ManagerDelegate.java` contains the methods that the `ViewManager` can call on the custom Native Component - the `ManagerInterface.java` contains the interface of the `ViewManager`. -In the folder whose name was setup in the `codegenConfig.android.javaPackageName`, instead, you can find the abstract class that a Turbo Native Module has to implement to carry out its tasks. +In the folder whose name was set up in the `codegenConfig.android.javaPackageName`, instead, you can find the abstract class that a Turbo Native Module has to implement to carry out its tasks. In the `jni` folder, finally, there is all the boilerplate code to connect JS to Android. @@ -200,7 +200,7 @@ build └── States.h ``` -Part of these generated files are used by React Native in the Core. Then there are a set of files which contains the same name you specified in the package.json `codegenConfig.name` field. +Part of these generated files are used by React Native in the Core. Then there is a set of files which contains the same name you specified in the package.json `codegenConfig.name` field. - `/.h`: this contains the interface of your custom iOS Turbo Native Modules. - `/-generated.mm`: this contains the glue code of your custom iOS Turbo Native Modules. diff --git a/docs/the-new-architecture/what-is-codegen.md b/docs/the-new-architecture/what-is-codegen.md index dfd33229b4f..d83ff7ef572 100644 --- a/docs/the-new-architecture/what-is-codegen.md +++ b/docs/the-new-architecture/what-is-codegen.md @@ -8,8 +8,8 @@ React Native invokes **Codegen** automatically every time an iOS or Android app ## How does Codegen works -**Codegen** is a process that is tightly coupled with a React Native app. The **Codegen** scripts live inside the `react-native` NPM package and the apps calls those scripts at build time. +**Codegen** is a process that is tightly coupled with a React Native app. The **Codegen** scripts live inside the `react-native` NPM package and the apps call those scripts at build time. **Codegen** crawls the folders in your project, starting from a directory you specify in your `package.json`, looking for some specific JS files that contains the specification (or specs) for your custom modules and components. Spec files are JS files written in a typed dialect: React Native currently supports Flow and TypeScript. -Every time **Codegen** finds a spec files, it generates the boilerplate code associated to it. **Codegen** generates some C++ glue-code and then it generates platform-specific code, using Java for Android and Objective-C++ for iOS. +Every time **Codegen** finds a spec file, it generates the boilerplate code associated to it. **Codegen** generates some C++ glue-code and then it generates platform-specific code, using Java for Android and Objective-C++ for iOS. diff --git a/docs/timers.md b/docs/timers.md index c025887fe89..2dbfff20689 100644 --- a/docs/timers.md +++ b/docs/timers.md @@ -20,7 +20,7 @@ The `Promise` implementation uses `setImmediate` as its asynchronicity implement :::note When debugging on Android, if the times between the debugger and device have drifted; things such as animation, event behavior, etc., might not work properly or the results may not be accurate. -Please correct this by running `` adb shell "date `date +%m%d%H%M%Y.%S%3N`" `` on your debugger machine. Root access is required for the use in real device. +Please correct this by running ``adb shell "date `date +%m%d%H%M%Y.%S%3N`"`` on your debugger machine. Root access is required for the use in real device. ::: ## InteractionManager diff --git a/docs/toastandroid.md b/docs/toastandroid.md index 6207921641a..9ca5e906d71 100644 --- a/docs/toastandroid.md +++ b/docs/toastandroid.md @@ -12,6 +12,8 @@ You can alternatively use `showWithGravity(message, duration, gravity)` to speci The `showWithGravityAndOffset(message, duration, gravity, xOffset, yOffset)` method adds the ability to specify an offset with in pixels. +> Starting with Android 11 (API level 30), setting the gravity has no effect on text toasts. Read about the changes [here](https://developer.android.com/about/versions/11/behavior-changes-11#text-toast-api-changes). + ```SnackPlayer name=Toast%20Android%20API%20Example&supportedPlatforms=android import React from 'react'; import {StyleSheet, ToastAndroid, Button, StatusBar} from 'react-native'; @@ -86,6 +88,8 @@ static show(message: string, duration: number); ### `showWithGravity()` +This property will only work on Android API 29 and below. For similar functionality on higher Android APIs, consider using snackbar or notification. + ```tsx static showWithGravity(message: string, duration: number, gravity: number); ``` @@ -94,6 +98,8 @@ static showWithGravity(message: string, duration: number, gravity: number); ### `showWithGravityAndOffset()` +This property will only work on Android API 29 and below. For similar functionality on higher Android APIs, consider using snackbar or notification. + ```tsx static showWithGravityAndOffset( message: string, diff --git a/docs/touchablewithoutfeedback.md b/docs/touchablewithoutfeedback.md index 977375e08da..1096aa7c695 100644 --- a/docs/touchablewithoutfeedback.md +++ b/docs/touchablewithoutfeedback.md @@ -84,7 +84,11 @@ export default TouchableWithoutFeedbackExample; ## Props -### `accessibilityIgnoresInvertColors` +### `accessibilityIgnoresInvertColors`
iOS
+ +A value indicating this view should or should not be inverted when color inversion is turned on. A value of `true` will tell the view to not be inverted even if color inversion is turned on. + +See the [Accessibility guide](accessibility.md#accessibilityignoresinvertcolors) for more information. | Type | | ------- | diff --git a/docs/transforms.md b/docs/transforms.md index cfb51f6949f..77e72bec67c 100644 --- a/docs/transforms.md +++ b/docs/transforms.md @@ -211,13 +211,19 @@ The `transformOrigin` property sets the origin for a view's transformations. The # Example -```SnackPlayer name=TransformOrigin%20Example -import React, {useRef, useEffect} from 'react'; -import {Animated, View, StyleSheet, Easing} from 'react-native'; +```SnackPlayer name=TransformOrigin%20Example&supportedPlatforms=ios,android +import React, {useEffect} from 'react'; +import { + Animated, + View, + StyleSheet, + Easing, + useAnimatedValue, +} from 'react-native'; import {SafeAreaView, SafeAreaProvider} from 'react-native-safe-area-context'; const App = () => { - const rotateAnim = useRef(new Animated.Value(0)).current; + const rotateAnim = useAnimatedValue(0); useEffect(() => { Animated.loop( diff --git a/docs/turbo-native-modules-android.md b/docs/turbo-native-modules-android.md index 281eb200399..b8090adfed3 100644 --- a/docs/turbo-native-modules-android.md +++ b/docs/turbo-native-modules-android.md @@ -107,7 +107,7 @@ class NativeLocalStorageModule(reactContext: ReactApplicationContext) : NativeLo
-Next we need to create `NativeLocalStoragePackage`. It provides an object to register our Module in the React Native runtime, by wrapping it as a Turbo Native Package: +Next we need to create `NativeLocalStoragePackage`. It provides an object to register our Module in the React Native runtime, by wrapping it as a Base Native Package: @@ -115,7 +115,7 @@ Next we need to create `NativeLocalStoragePackage`. It provides an object to reg ```java title="android/app/src/main/java/com/nativelocalstorage/NativeLocalStoragePackage.java" package com.nativelocalstorage; -import com.facebook.react.TurboReactPackage; +import com.facebook.react.BaseReactPackage; import com.facebook.react.bridge.NativeModule; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.module.model.ReactModuleInfo; @@ -124,7 +124,7 @@ import com.facebook.react.module.model.ReactModuleInfoProvider; import java.util.HashMap; import java.util.Map; -public class NativeLocalStoragePackage extends TurboReactPackage { +public class NativeLocalStoragePackage extends BaseReactPackage { @Override public NativeModule getModule(String name, ReactApplicationContext reactContext) { @@ -162,13 +162,13 @@ public class NativeLocalStoragePackage extends TurboReactPackage { ```kotlin title="android/app/src/main/java/com/nativelocalstorage/NativeLocalStoragePackage.kt" package com.nativelocalstorage -import com.facebook.react.TurboReactPackage +import com.facebook.react.BaseReactPackage import com.facebook.react.bridge.NativeModule import com.facebook.react.bridge.ReactApplicationContext import com.facebook.react.module.model.ReactModuleInfo import com.facebook.react.module.model.ReactModuleInfoProvider -class NativeLocalStoragePackage : TurboReactPackage() { +class NativeLocalStoragePackage : BaseReactPackage() { override fun getModule(name: String, reactContext: ReactApplicationContext): NativeModule? = if (name == NativeLocalStorageModule.NAME) { @@ -200,7 +200,7 @@ Finally, we need to tell the React Native in our main application how to find th In this case, you add it to be returned by the [getPackages](https://github.com/facebook/react-native/blob/8d8b8c343e62115a5509e1aed62047053c2f6e39/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactNativeHost.java#L233) method. :::info -Later you’ll learn how to distribute your Turbo Native Modules as [npm packages](the-new-architecture/create-module-library.md#publish-the-library-on-npm), which our build tooling will autolink for you. +Later you’ll learn how to distribute your Native Modules as [npm packages](the-new-architecture/create-module-library.md#publish-the-library-on-npm), which our build tooling will autolink for you. ::: diff --git a/docs/turbo-native-modules.md b/docs/turbo-native-modules.md index 838dd90ebae..dc19603953b 100644 --- a/docs/turbo-native-modules.md +++ b/docs/turbo-native-modules.md @@ -63,7 +63,7 @@ export interface Spec extends TurboModule { export default TurboModuleRegistry.getEnforcing( 'NativeLocalStorage', -) as Spec; +); ``` diff --git a/docs/view.md b/docs/view.md index 9050bb8cf26..099c0080e87 100644 --- a/docs/view.md +++ b/docs/view.md @@ -361,13 +361,23 @@ Represents the textual description of the component. Has precedence over the `te --- -### `collapsable`
Android
+### `collapsable` Views that are only used to layout their children or otherwise don't draw anything may be automatically removed from the native hierarchy as an optimization. Set this property to `false` to disable this optimization and ensure that this `View` exists in the native view hierarchy. -| Type | -| ---- | -| bool | +| Type | Default | +| ------- | ------- | +| boolean | true | + +--- + +### `collapsableChildren` + +Setting to false prevents direct children of the view from being removed from the native view hierarchy, similar to the effect of setting `collapsable={false}` on each child. + +| Type | Default | +| ------- | ------- | +| boolean | true | --- @@ -522,7 +532,7 @@ When `accessible` is `true`, the system will invoke this function when the user --- -### `onAccessibilityTap` +### `onAccessibilityTap`
iOS
When `accessible` is true, the system will try to invoke this function when the user performs accessibility tap gesture. diff --git a/package.json b/package.json index c154b1ea7fb..95b77b24af3 100644 --- a/package.json +++ b/package.json @@ -22,22 +22,22 @@ } }, "dependencies": { - "babel-eslint": "^10.1.0", "case-police": "^0.5.14", "eslint": "^8.20.0", - "eslint-config-prettier": "^8.5.0", - "eslint-plugin-mdx": "^1.16.0", - "eslint-plugin-prettier": "^4.2.1", + "eslint-config-prettier": "^9.1.0", + "eslint-plugin-mdx": "^3.1.5", + "eslint-plugin-prettier": "^5.2.1", "eslint-plugin-yml": "^1.2.0", "husky": "^4.3.8", "netlify-plugin-cache": "^1.0.3", - "prettier": "^2.7.1", - "pretty-quick": "^3.1.3", + "prettier": "^3.4.2", + "pretty-quick": "^4.0.0", "yarn-deduplicate": "^5.0.0" }, "resolutions": { "trim": "^1.0.1", "update-notifier": "^6.0.2", "@sideway/formula": ">=3.0.1" - } + }, + "packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e" } diff --git a/plugins/remark-lint-no-dead-urls/package.json b/plugins/remark-lint-no-dead-urls/package.json index 6ee923e1c57..c42069a21af 100644 --- a/plugins/remark-lint-no-dead-urls/package.json +++ b/plugins/remark-lint-no-dead-urls/package.json @@ -14,7 +14,7 @@ "src/*" ], "scripts": { - "prettier": "prettier --write \"{src/**/*.js,tests/**/*.js,*.md}\"", + "prettier": "prettier --write '{src,tests}/**/*.{md,js,jsx,ts,tsx}'", "test": "yarn node --experimental-vm-modules $(yarn bin jest)" }, "dependencies": { diff --git a/plugins/remark-snackplayer/package.json b/plugins/remark-snackplayer/package.json index a2d50cb0690..366cdf3afdf 100644 --- a/plugins/remark-snackplayer/package.json +++ b/plugins/remark-snackplayer/package.json @@ -15,7 +15,7 @@ "src" ], "scripts": { - "prettier": "prettier --write \"{src/**/*.js,tests/**/*.js,*.md}\"", + "prettier": "prettier --write '{src,tests}/**/*.{md,js,jsx,ts,tsx}'", "test": "yarn tape tests/index.js" }, "dependencies": { diff --git a/website/.remarkrc.mjs b/website/.remarkrc.mjs index 9361cad8394..f019fea1116 100644 --- a/website/.remarkrc.mjs +++ b/website/.remarkrc.mjs @@ -2,20 +2,21 @@ import packageJson from "./package.json" assert { type: "json" }; export default { plugins: [ - [ - "@react-native-website/remark-lint-no-broken-external-links", - { - skipUrlPatterns: [ - // False positive, flagged as a bot and rate limited - "www.apkfiles.com", - // TODO: replace the 2048 example repository with another suitable project - "github.com/JoelMarcey", - ], - baseUrl: "https://reactnative.dev/docs", - headers: { - "user-agent": `${packageJson.name}/${packageJson.version}`, - }, - }, - ], + // TODO: Enable the plugin once a more performant solution is found + // [ + // "@react-native-website/remark-lint-no-broken-external-links", + // { + // skipUrlPatterns: [ + // // False positive, flagged as a bot and rate limited + // "www.apkfiles.com", + // // TODO: replace the 2048 example repository with another suitable project + // "github.com/JoelMarcey", + // ], + // baseUrl: "https://reactnative.dev/docs", + // headers: { + // "user-agent": `${packageJson.name}/${packageJson.version}`, + // }, + // }, + // ], ], }; diff --git a/website/architecture/landing-page.md b/website/architecture/landing-page.md index b7e7e5e31b4..2cb2231740a 100644 --- a/website/architecture/landing-page.md +++ b/website/architecture/landing-page.md @@ -209,7 +209,7 @@ You can follow along and contribute in our dedicated [discussions & proposals](h With 0.76, The New Architecture is enabled by default in all the React Native projects. -If you find aything that is not working well, please open an issue using [this template](https://github.com/facebook/react-native/issues/new?assignees=&labels=Needs%3A+Triage+%3Amag%3A%2CType%3A+New+Architecture&projects=&template=new_architecture_bug_report.yml). +If you find anything that is not working well, please open an issue using [this template](https://github.com/facebook/react-native/issues/new?assignees=&labels=Needs%3A+Triage+%3Amag%3A%2CType%3A+New+Architecture&projects=&template=new_architecture_bug_report.yml). If, for any reasons, you can't use the New Architecture, you can still opt-out from it: @@ -232,12 +232,14 @@ If, for any reasons, you can't use the New Architecture, you can still opt-out f 1. Open the `ios/Podfile` file 2. Add `ENV['RCT_NEW_ARCH_ENABLED'] = '0'` in the main scope of the Podfile ([reference Podfile](https://github.com/react-native-community/template/blob/0.76-stable/template/ios/Podfile) in the template) + ```diff + ENV['RCT_NEW_ARCH_ENABLED'] = '0' # Resolve react_native_pods.rb with node to allow for hoisting require Pod::Executable.execute_command('node', ['-p', 'require.resolve( ``` + 3. Install your CocoaPods dependencies with the command: ```shell diff --git a/website/blog/2017-03-13-idx-the-existential-function.md b/website/blog/2017-03-13-idx-the-existential-function.md index 9bb8bac1410..650fbe4166e 100644 --- a/website/blog/2017-03-13-idx-the-existential-function.md +++ b/website/blog/2017-03-13-idx-the-existential-function.md @@ -40,10 +40,10 @@ In practice, try-catching every nested property access is slow, and differentiat props.user == null ? props.user : props.user.friends == null - ? props.user.friends - : props.user.friends[0] == null - ? props.user.friends[0] - : props.user.friends[0].friends; + ? props.user.friends + : props.user.friends[0] == null + ? props.user.friends[0] + : props.user.friends[0].friends; ``` Finally, we added a custom Flow type declaration for `idx` that allows the traversal in the second argument to be properly type-checked while permitting nested access on nullable properties. diff --git a/website/blog/authors.yml b/website/blog/authors.yml index 0c10f2d122f..8034baea675 100644 --- a/website/blog/authors.yml +++ b/website/blog/authors.yml @@ -155,7 +155,7 @@ huntie: name: Alex Hunt title: Software Engineer at Meta socials: - x: alxhnt + x: huntie github: huntie image_url: https://github.com/huntie.png diff --git a/website/contributing/how-to-open-a-pull-request.md b/website/contributing/how-to-open-a-pull-request.md index 408fa16ea38..1b3eeb6224e 100644 --- a/website/contributing/how-to-open-a-pull-request.md +++ b/website/contributing/how-to-open-a-pull-request.md @@ -77,11 +77,15 @@ IDE project configurations: - **Android Studio**: Open the repo root folder (containing the `.idea` config directory). - **Xcode**: Open `packages/rn-tester/RNTesterPods.xcworkspace`. -### 3. Test your changes +### 3. Run your changes + +The package rn-tester can be used to run and validate your changes. You can learn more in [RNTester readme](https://github.com/facebook/react-native/blob/main/packages/rn-tester/README.md). + +### 4. Test your changes Make sure your changes are correct and do not introduce any test failures. You can learn more in [Running and Writing Tests](/contributing/how-to-run-and-write-tests). -### 4. Lint your code +### 5. Lint your code We understand it can take a while to ramp up and get a sense of the style followed for each of the languages in use in the core React Native repository. Developers should not need to worry about minor nits, so whenever possible, we use tools that automate the process of rewriting your code to follow conventions. @@ -91,7 +95,7 @@ We also use a linter to catch styling issues that may exist in your code. You ca To learn more about coding conventions, refer to the [Coding Style guide](/contributing/how-to-contribute-code#coding-style). -### 5. View your changes +### 6. View your changes Many popular editors integrate with source control in some way. You can also use `git status` and `git diff` on the command line to keep track of what has changed. diff --git a/website/core/DocsRating.js b/website/core/DocsRating.tsx similarity index 98% rename from website/core/DocsRating.js rename to website/core/DocsRating.tsx index 95aa627e6b9..e78e1aca6a3 100644 --- a/website/core/DocsRating.js +++ b/website/core/DocsRating.tsx @@ -37,7 +37,7 @@ const DocsRating = ({label}) => { Is this page useful? giveFeedback(1)} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 81.13 89.76"> @@ -45,7 +45,7 @@ const DocsRating = ({label}) => { giveFeedback(0)} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 81.13 89.76"> diff --git a/website/core/PlatformTag.js b/website/core/PlatformTag.tsx similarity index 100% rename from website/core/PlatformTag.js rename to website/core/PlatformTag.tsx diff --git a/website/core/PrismTheme.js b/website/core/PrismTheme.ts similarity index 94% rename from website/core/PrismTheme.js rename to website/core/PrismTheme.ts index adce7234e57..f3ae53172f2 100644 --- a/website/core/PrismTheme.js +++ b/website/core/PrismTheme.ts @@ -5,7 +5,9 @@ * LICENSE file in the root directory of this source tree. */ -const theme = { +import type {ThemeConfig} from '@docusaurus/preset-classic'; + +const theme: ThemeConfig['prism']['theme'] = { plain: { color: '#FFFFFF', backgroundColor: '#282C34', @@ -123,4 +125,4 @@ const theme = { ], }; -module.exports = theme; +export default theme; diff --git a/website/core/TableRowWithCodeBlock.js b/website/core/TableRowWithCodeBlock.tsx similarity index 100% rename from website/core/TableRowWithCodeBlock.js rename to website/core/TableRowWithCodeBlock.tsx diff --git a/website/core/TabsConstants.js b/website/core/TabsConstants.tsx similarity index 100% rename from website/core/TabsConstants.js rename to website/core/TabsConstants.tsx diff --git a/website/core/VerticalTable.js b/website/core/VerticalTable.tsx similarity index 100% rename from website/core/VerticalTable.js rename to website/core/VerticalTable.tsx diff --git a/website/docusaurus.config.js b/website/docusaurus.config.js deleted file mode 100644 index 148d14fb052..00000000000 --- a/website/docusaurus.config.js +++ /dev/null @@ -1,454 +0,0 @@ -/** - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -const users = require('./showcase.json'); -const versions = require('./versions.json'); - -const lastVersion = versions[0]; -const copyright = `Copyright © ${new Date().getFullYear()} Meta Platforms, Inc.`; - -const commonDocsOptions = { - breadcrumbs: false, - showLastUpdateAuthor: false, - showLastUpdateTime: true, - editUrl: - 'https://github.com/facebook/react-native-website/blob/main/website/', - remarkPlugins: [require('@react-native-website/remark-snackplayer')], -}; - -const isDeployPreview = process.env.PREVIEW_DEPLOY === 'true'; - -/** @type {import('@docusaurus/types').DocusaurusConfig} */ -module.exports = { - title: 'React Native', - tagline: 'A framework for building native apps using React', - organizationName: 'facebook', - projectName: 'react-native', - url: 'https://reactnative.dev', - baseUrl: '/', - clientModules: [ - require.resolve('./modules/snackPlayerInitializer.js'), - require.resolve('./modules/jumpToFragment.js'), - ], - trailingSlash: false, // because trailing slashes can break some existing relative links - scripts: [ - { - src: 'https://cdn.jsdelivr.net/npm/focus-visible@5.2.0/dist/focus-visible.min.js', - defer: true, - }, - { - src: 'https://widget.surveymonkey.com/collect/website/js/tRaiETqnLgj758hTBazgd8ryO5qrZo8Exadq9qmt1wtm4_2FdZGEAKHDFEt_2BBlwwM4.js', - defer: true, - }, - {src: 'https://snack.expo.dev/embed.js', defer: true}, - {src: 'https://platform.twitter.com/widgets.js', async: true}, - ], - favicon: 'img/favicon.ico', - titleDelimiter: '·', - customFields: { - users, - facebookAppId: '1677033832619985', - }, - i18n: { - defaultLocale: 'en', - locales: ['en'], - }, - onBrokenLinks: 'throw', - webpack: { - jsLoader: isServer => ({ - loader: require.resolve('esbuild-loader'), - options: { - loader: 'tsx', - format: isServer ? 'cjs' : undefined, - target: isServer ? 'node16' : 'es2020', - jsx: 'automatic', - }, - }), - }, - presets: [ - [ - '@docusaurus/preset-classic', - /** @type {import('@docusaurus/preset-classic').Options} */ - ({ - docs: { - path: '../docs', - sidebarPath: require.resolve('./sidebars.json'), - editCurrentVersion: true, - onlyIncludeVersions: isDeployPreview - ? ['current', ...versions.slice(0, 2)] - : undefined, - versions: { - [lastVersion]: { - badge: false, // Do not show version badge for last RN version - }, - }, - ...commonDocsOptions, - }, - blog: { - path: 'blog', - blogSidebarCount: 'ALL', - blogSidebarTitle: 'All Blog Posts', - feedOptions: { - type: 'all', - copyright, - }, - onInlineAuthors: 'ignore', - // Ignore for now due to old posts - onUntruncatedBlogPosts: 'ignore', - }, - theme: { - customCss: [ - require.resolve('./src/css/customTheme.scss'), - require.resolve('./src/css/index.scss'), - require.resolve('./src/css/showcase.scss'), - require.resolve('./src/css/versions.scss'), - ], - }, - // TODO: GA is deprecated, remove once we're sure data is streaming in GA4 via gtag. - googleAnalytics: { - trackingID: 'UA-41298772-2', - }, - gtag: { - trackingID: 'G-58L13S6BDP', - }, - }), - ], - ], - plugins: [ - 'docusaurus-plugin-sass', - [ - 'content-docs', - /** @type {import('@docusaurus/plugin-content-docs').Options} */ - ({ - id: 'architecture', - path: 'architecture', - routeBasePath: '/architecture', - sidebarPath: require.resolve('./sidebarsArchitecture.json'), - ...commonDocsOptions, - }), - ], - [ - 'content-docs', - /** @type {import('@docusaurus/plugin-content-docs').Options} */ - ({ - id: 'contributing', - path: 'contributing', - routeBasePath: '/contributing', - sidebarPath: require.resolve('./sidebarsContributing.json'), - ...commonDocsOptions, - }), - ], - [ - 'content-docs', - /** @type {import('@docusaurus/plugin-content-docs').Options} */ - ({ - id: 'community', - path: 'community', - routeBasePath: '/community', - sidebarPath: require.resolve('./sidebarsCommunity.json'), - ...commonDocsOptions, - }), - ], - [ - '@docusaurus/plugin-pwa', - { - debug: true, - offlineModeActivationStrategies: ['appInstalled', 'queryString'], - pwaHead: [ - { - tagName: 'link', - rel: 'icon', - href: '/img/pwa/manifest-icon-512.png', - }, - { - tagName: 'link', - rel: 'manifest', - href: '/manifest.json', - }, - { - tagName: 'meta', - name: 'theme-color', - content: '#20232a', - }, - { - tagName: 'meta', - name: 'apple-mobile-web-app-capable', - content: 'yes', - }, - { - tagName: 'meta', - name: 'apple-mobile-web-app-status-bar-style', - content: '#20232a', - }, - { - tagName: 'link', - rel: 'apple-touch-icon', - href: '/img/pwa/manifest-icon-512.png', - }, - { - tagName: 'link', - rel: 'mask-icon', - href: '/img/pwa/manifest-icon-512.png', - color: '#06bcee', - }, - { - tagName: 'meta', - name: 'msapplication-TileImage', - href: '/img/pwa/manifest-icon-512.png', - }, - { - tagName: 'meta', - name: 'msapplication-TileColor', - content: '#20232a', - }, - ], - }, - ], - ], - themeConfig: - /** @type {import('@docusaurus/preset-classic').ThemeConfig} */ - ({ - colorMode: { - defaultMode: 'light', - disableSwitch: false, - respectPrefersColorScheme: true, - }, - announcementBar: { - id: 'new-architecture', - content: - 'The New Architecture has arrived - learn more', - backgroundColor: '#20232a', - textColor: '#fff', - isCloseable: false, - }, - prism: { - defaultLanguage: 'jsx', - theme: require('./core/PrismTheme'), - additionalLanguages: [ - 'diff', - 'bash', - 'json', - 'java', - 'kotlin', - 'objectivec', - 'swift', - 'groovy', - 'ruby', - 'flow', - ], - magicComments: [ - { - className: 'theme-code-block-highlighted-line', - line: 'highlight-next-line', - block: {start: 'highlight-start', end: 'highlight-end'}, - }, - { - className: 'code-add-line', - line: 'highlight-add-next-line', - block: {start: 'highlight-add-start', end: 'highlight-add-end'}, - }, - { - className: 'code-remove-line', - line: 'highlight-remove-next-line', - block: { - start: 'highlight-remove-start', - end: 'highlight-remove-end', - }, - }, - ], - }, - navbar: { - title: 'React Native', - logo: { - src: 'img/header_logo.svg', - alt: 'React Native', - }, - style: 'dark', - items: [ - { - label: 'Development', - type: 'dropdown', - position: 'right', - items: [ - { - label: 'Guides', - type: 'doc', - docId: 'getting-started', - }, - { - label: 'Components', - type: 'doc', - docId: 'components-and-apis', - }, - { - label: 'APIs', - type: 'doc', - docId: 'accessibilityinfo', - }, - { - label: 'Architecture', - type: 'doc', - docId: 'architecture-overview', - docsPluginId: 'architecture', - }, - ], - }, - { - type: 'doc', - docId: 'overview', - label: 'Contributing', - position: 'right', - docsPluginId: 'contributing', - }, - { - type: 'doc', - docId: 'overview', - label: 'Community', - position: 'right', - docsPluginId: 'community', - }, - { - to: '/showcase', - label: 'Showcase', - position: 'right', - }, - { - to: '/blog', - label: 'Blog', - position: 'right', - }, - { - type: 'docsVersionDropdown', - position: 'left', - dropdownActiveClassDisabled: true, - dropdownItemsAfter: [ - { - to: '/versions', - label: 'All versions', - }, - ], - }, - { - href: 'https://github.com/facebook/react-native', - 'aria-label': 'GitHub repository', - position: 'right', - className: 'navbar-github-link', - }, - ], - }, - image: 'img/logo-og.png', - footer: { - style: 'dark', - links: [ - { - title: 'Develop', - items: [ - { - label: 'Guides', - to: 'docs/getting-started', - }, - { - label: 'Components', - to: 'docs/components-and-apis', - }, - { - label: 'APIs', - to: 'docs/accessibilityinfo', - }, - { - label: 'Architecture', - to: 'architecture/overview', - }, - ], - }, - { - title: 'Participate', - items: [ - { - label: 'Showcase', - to: 'showcase', - }, - { - label: 'Contributing', - to: 'contributing/overview', - }, - { - label: 'Community', - to: 'community/overview', - }, - { - label: 'Directory', - href: 'https://reactnative.directory/', - }, - { - label: 'Stack Overflow', - href: 'https://stackoverflow.com/questions/tagged/react-native', - }, - ], - }, - { - title: 'Find us', - items: [ - { - label: 'Blog', - to: 'blog', - }, - { - label: 'X', - href: 'https://x.com/reactnative', - }, - { - label: 'GitHub', - href: 'https://github.com/facebook/react-native', - }, - ], - }, - { - title: 'Explore More', - items: [ - { - label: 'ReactJS', - href: 'https://react.dev/', - }, - { - label: 'Privacy Policy', - href: 'https://opensource.fb.com/legal/privacy/', - }, - { - label: 'Terms of Service', - href: 'https://opensource.fb.com/legal/terms/', - }, - ], - }, - ], - logo: { - alt: 'Meta Open Source Logo', - src: 'img/oss_logo.svg', - href: 'https://opensource.fb.com/', - }, - copyright, - }, - algolia: { - appId: '8TDSE0OHGQ', - apiKey: '83cd239c72f9f8b0ed270a04b1185288', - indexName: 'react-native-v2', - contextualSearch: true, - }, - metadata: [ - { - property: 'og:image', - content: 'https://reactnative.dev/img/logo-og.png', - }, - {name: 'twitter:card', content: 'summary_large_image'}, - { - name: 'twitter:image', - content: 'https://reactnative.dev/img/logo-og.png', - }, - {name: 'twitter:site', content: '@reactnative'}, - ], - }), -}; diff --git a/website/docusaurus.config.ts b/website/docusaurus.config.ts new file mode 100644 index 00000000000..83ff71a1806 --- /dev/null +++ b/website/docusaurus.config.ts @@ -0,0 +1,452 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import type {Config} from '@docusaurus/types'; +import type * as Preset from '@docusaurus/preset-classic'; + +import users from './showcase.json'; +import versions from './versions.json'; + +const lastVersion = versions[0]; +const copyright = `Copyright © ${new Date().getFullYear()} Meta Platforms, Inc.`; + +const commonDocsOptions = { + breadcrumbs: false, + showLastUpdateAuthor: false, + showLastUpdateTime: true, + editUrl: + 'https://github.com/facebook/react-native-website/blob/main/website/', + remarkPlugins: [require('@react-native-website/remark-snackplayer')], +}; + +const isDeployPreview = process.env.PREVIEW_DEPLOY === 'true'; + +const config: Config = { + future: { + // Make Docusaurus build faster - enabled by default + // See https://github.com/facebook/docusaurus/issues/10556 + // See https://github.com/facebook/react-native-website/pull/4268 + // See https://docusaurus.io/blog/releases/3.6 + experimental_faster: (process.env.DOCUSAURUS_FASTER ?? 'true') === 'true', + }, + + title: 'React Native', + tagline: 'A framework for building native apps using React', + organizationName: 'facebook', + projectName: 'react-native', + url: 'https://reactnative.dev', + baseUrl: '/', + clientModules: [ + require.resolve('./modules/snackPlayerInitializer.js'), + require.resolve('./modules/jumpToFragment.js'), + ], + trailingSlash: false, // because trailing slashes can break some existing relative links + scripts: [ + { + src: 'https://cdn.jsdelivr.net/npm/focus-visible@5.2.0/dist/focus-visible.min.js', + defer: true, + }, + { + src: 'https://widget.surveymonkey.com/collect/website/js/tRaiETqnLgj758hTBazgd8ryO5qrZo8Exadq9qmt1wtm4_2FdZGEAKHDFEt_2BBlwwM4.js', + defer: true, + }, + {src: 'https://snack.expo.dev/embed.js', defer: true}, + {src: 'https://platform.twitter.com/widgets.js', async: true}, + ], + favicon: 'img/favicon.ico', + titleDelimiter: '·', + customFields: { + users, + facebookAppId: '1677033832619985', + }, + i18n: { + defaultLocale: 'en', + locales: ['en'], + }, + onBrokenLinks: 'throw', + presets: [ + [ + '@docusaurus/preset-classic', + { + docs: { + path: '../docs', + sidebarPath: require.resolve('./sidebars'), + editCurrentVersion: true, + onlyIncludeVersions: isDeployPreview + ? ['current', ...versions.slice(0, 2)] + : undefined, + versions: { + [lastVersion]: { + badge: false, // Do not show version badge for last RN version + }, + }, + ...commonDocsOptions, + }, + blog: { + path: 'blog', + blogSidebarCount: 'ALL', + blogSidebarTitle: 'All Blog Posts', + feedOptions: { + type: 'all', + copyright, + }, + onInlineAuthors: 'ignore', + // Ignore for now due to old posts + onUntruncatedBlogPosts: 'ignore', + }, + theme: { + customCss: [ + require.resolve('./src/css/customTheme.scss'), + require.resolve('./src/css/index.scss'), + require.resolve('./src/css/showcase.scss'), + require.resolve('./src/css/versions.scss'), + ], + }, + // TODO: GA is deprecated, remove once we're sure data is streaming in GA4 via gtag. + googleAnalytics: { + trackingID: 'UA-41298772-2', + }, + gtag: { + trackingID: 'G-58L13S6BDP', + }, + } satisfies Preset.Options, + ], + ], + plugins: [ + 'docusaurus-plugin-sass', + [ + 'content-docs', + /** @type {import('@docusaurus/plugin-content-docs').Options} */ + { + id: 'architecture', + path: 'architecture', + routeBasePath: '/architecture', + sidebarPath: require.resolve('./sidebarsArchitecture'), + ...commonDocsOptions, + }, + ], + [ + 'content-docs', + /** @type {import('@docusaurus/plugin-content-docs').Options} */ + { + id: 'contributing', + path: 'contributing', + routeBasePath: '/contributing', + sidebarPath: require.resolve('./sidebarsContributing'), + ...commonDocsOptions, + }, + ], + [ + 'content-docs', + /** @type {import('@docusaurus/plugin-content-docs').Options} */ + { + id: 'community', + path: 'community', + routeBasePath: '/community', + sidebarPath: require.resolve('./sidebarsCommunity'), + ...commonDocsOptions, + }, + ], + [ + '@docusaurus/plugin-pwa', + { + debug: true, + offlineModeActivationStrategies: ['appInstalled', 'queryString'], + pwaHead: [ + { + tagName: 'link', + rel: 'icon', + href: '/img/pwa/manifest-icon-512.png', + }, + { + tagName: 'link', + rel: 'manifest', + href: '/manifest.json', + }, + { + tagName: 'meta', + name: 'theme-color', + content: '#20232a', + }, + { + tagName: 'meta', + name: 'apple-mobile-web-app-capable', + content: 'yes', + }, + { + tagName: 'meta', + name: 'apple-mobile-web-app-status-bar-style', + content: '#20232a', + }, + { + tagName: 'link', + rel: 'apple-touch-icon', + href: '/img/pwa/manifest-icon-512.png', + }, + { + tagName: 'link', + rel: 'mask-icon', + href: '/img/pwa/manifest-icon-512.png', + color: '#06bcee', + }, + { + tagName: 'meta', + name: 'msapplication-TileImage', + href: '/img/pwa/manifest-icon-512.png', + }, + { + tagName: 'meta', + name: 'msapplication-TileColor', + content: '#20232a', + }, + ], + }, + ], + ], + themeConfig: { + colorMode: { + defaultMode: 'light', + disableSwitch: false, + respectPrefersColorScheme: true, + }, + announcementBar: { + id: 'new-architecture', + content: + 'The New Architecture has arrived - learn more', + backgroundColor: '#20232a', + textColor: '#fff', + isCloseable: false, + }, + prism: { + defaultLanguage: 'jsx', + theme: require('./core/PrismTheme'), + additionalLanguages: [ + 'diff', + 'bash', + 'json', + 'java', + 'kotlin', + 'objectivec', + 'swift', + 'groovy', + 'ruby', + 'flow', + ], + magicComments: [ + { + className: 'theme-code-block-highlighted-line', + line: 'highlight-next-line', + block: {start: 'highlight-start', end: 'highlight-end'}, + }, + { + className: 'code-add-line', + line: 'highlight-add-next-line', + block: {start: 'highlight-add-start', end: 'highlight-add-end'}, + }, + { + className: 'code-remove-line', + line: 'highlight-remove-next-line', + block: { + start: 'highlight-remove-start', + end: 'highlight-remove-end', + }, + }, + ], + }, + navbar: { + title: 'React Native', + logo: { + src: 'img/header_logo.svg', + alt: 'React Native', + }, + style: 'dark', + items: [ + { + label: 'Development', + type: 'dropdown', + position: 'right', + items: [ + { + label: 'Guides', + type: 'doc', + docId: 'getting-started', + }, + { + label: 'Components', + type: 'doc', + docId: 'components-and-apis', + }, + { + label: 'APIs', + type: 'doc', + docId: 'accessibilityinfo', + }, + { + label: 'Architecture', + type: 'doc', + docId: 'architecture-overview', + docsPluginId: 'architecture', + }, + ], + }, + { + type: 'doc', + docId: 'overview', + label: 'Contributing', + position: 'right', + docsPluginId: 'contributing', + }, + { + type: 'doc', + docId: 'overview', + label: 'Community', + position: 'right', + docsPluginId: 'community', + }, + { + to: '/showcase', + label: 'Showcase', + position: 'right', + }, + { + to: '/blog', + label: 'Blog', + position: 'right', + }, + { + type: 'docsVersionDropdown', + position: 'left', + dropdownActiveClassDisabled: true, + dropdownItemsAfter: [ + { + to: '/versions', + label: 'All versions', + }, + ], + }, + { + href: 'https://github.com/facebook/react-native', + 'aria-label': 'GitHub repository', + position: 'right', + className: 'navbar-github-link', + }, + ], + }, + image: 'img/logo-share.png', + footer: { + style: 'dark', + links: [ + { + title: 'Develop', + items: [ + { + label: 'Guides', + to: 'docs/getting-started', + }, + { + label: 'Components', + to: 'docs/components-and-apis', + }, + { + label: 'APIs', + to: 'docs/accessibilityinfo', + }, + { + label: 'Architecture', + to: 'architecture/overview', + }, + ], + }, + { + title: 'Participate', + items: [ + { + label: 'Showcase', + to: 'showcase', + }, + { + label: 'Contributing', + to: 'contributing/overview', + }, + { + label: 'Community', + to: 'community/overview', + }, + { + label: 'Directory', + href: 'https://reactnative.directory/', + }, + { + label: 'Stack Overflow', + href: 'https://stackoverflow.com/questions/tagged/react-native', + }, + ], + }, + { + title: 'Find us', + items: [ + { + label: 'Blog', + to: 'blog', + }, + { + label: 'X', + href: 'https://x.com/reactnative', + }, + { + label: 'GitHub', + href: 'https://github.com/facebook/react-native', + }, + ], + }, + { + title: 'Explore More', + items: [ + { + label: 'ReactJS', + href: 'https://react.dev/', + }, + { + label: 'Privacy Policy', + href: 'https://opensource.fb.com/legal/privacy/', + }, + { + label: 'Terms of Service', + href: 'https://opensource.fb.com/legal/terms/', + }, + ], + }, + ], + logo: { + alt: 'Meta Open Source Logo', + src: 'img/oss_logo.svg', + href: 'https://opensource.fb.com/', + }, + copyright, + }, + algolia: { + appId: '8TDSE0OHGQ', + apiKey: '83cd239c72f9f8b0ed270a04b1185288', + indexName: 'react-native-v2', + contextualSearch: true, + }, + metadata: [ + { + property: 'og:image', + content: 'https://reactnative.dev/img/logo-share.png', + }, + {name: 'twitter:card', content: 'summary_large_image'}, + { + name: 'twitter:image', + content: 'https://reactnative.dev/img/logo-share.png', + }, + {name: 'twitter:site', content: '@reactnative'}, + ], + } satisfies Preset.ThemeConfig, +}; + +module.exports = config; diff --git a/website/package.json b/website/package.json index fa7e2ee7909..7fb88ab57ac 100644 --- a/website/package.json +++ b/website/package.json @@ -14,23 +14,24 @@ "start": "docusaurus start", "build": "docusaurus build && yarn run update-redirect ./build/_redirects ./versions.json", "build:fast": "PREVIEW_DEPLOY=true yarn run build", + "tsc": "npx tsc --noEmit", "swizzle": "docusaurus swizzle", "deploy": "docusaurus deploy", "serve": "docusaurus serve", "clear": "docusaurus clear", "test": "yarn build", "version:cut": "docusaurus docs:version", - "format:source": "prettier --write {{core,src}/**/*.js,*.js}", + "format:source": "prettier --write '{core,src}/**/*.{js,jsx,ts,tsx}'", "format:markdown": "prettier --write ../docs/*.md && prettier --write {versioned_docs/**/*.md,blog/*.md}", "format:style": "prettier --write src/**/*.{scss,css}", "format:examples": "eslint-examples-js --fix && eslint-examples-tsx --fix", "prettier": "yarn format:source && yarn format:markdown && yarn format:style", - "lint": "eslint ../docs/** blog/** core/** src/**/*.js ./*.js", + "lint": "eslint ../docs/** blog/** '{core,src}/**/*.{js,jsx,ts,tsx}'", "lint:examples": "eslint-examples-js && eslint-examples-tsx && tsc-examples", "lint:versioned": "eslint versioned_docs/**", "lint:markdown": "remark ../docs --quiet -r .remarkrc.mjs", "lint:markdown:versioned": "remark ./versioned_docs --quiet -r .remarkrc.mjs", - "lint:format": "prettier --check {{core,src}/**/*.js,*.js} ../docs/*.md {versioned_docs/**/*.md,blog/*.md} src/**/*.{scss,css}", + "lint:format": "prettier --check '{core,src}/**/*.{js,jsx,ts,tsx}' ../docs/*.md {versioned_docs/**/*.md,blog/*.md} src/**/*.{scss,css}", "language:lint": "cd ../ && alex && case-police 'docs/*.md' -p brands,general,products,softwares -d ./website/react-native-dict.json", "language:lint:versioned": "cd ../ && alex . && case-police '**/*.md' -p brands,general,products,softwares -d ./website/react-native-dict.json", "ci:lint": "yarn lint && yarn lint:examples && yarn lint:versioned && yarn language:lint:versioned && yarn lint:markdown && yarn lint:format", @@ -49,27 +50,30 @@ ] }, "dependencies": { - "@docusaurus/core": "3.5.2", - "@docusaurus/plugin-google-gtag": "3.5.2", - "@docusaurus/plugin-pwa": "3.5.2", - "@docusaurus/preset-classic": "3.5.2", + "@docusaurus/core": "3.6.3", + "@docusaurus/faster": "3.6.3", + "@docusaurus/plugin-google-gtag": "3.6.3", + "@docusaurus/plugin-pwa": "3.6.3", + "@docusaurus/preset-classic": "3.6.3", "docusaurus-plugin-sass": "^0.2.5", - "esbuild-loader": "^2.21.0", "react": "^18.2.0", "react-dom": "^18.2.0", "react-github-btn": "^1.4.0", "sass": "1.76.0" }, "devDependencies": { - "@docusaurus/types": "3.5.2", + "@docusaurus/module-type-aliases": "3.6.3", + "@docusaurus/tsconfig": "3.6.3", + "@docusaurus/types": "3.6.3", "@react-native-website/lint-examples": "0.0.0", "@react-native-website/update-redirects": "0.0.0", + "@types/google.analytics": "^0.0.46", "alex": "^10.0.0", "fs-extra": "^10.1.0", "glob": "^8.0.3", "glob-promise": "^4.2.2", "path": "^0.12.7", - "remark-cli": "^11.0.0", - "remark-lint-no-dead-urls": "^1.1.0" + "remark-cli": "^12.0.1", + "typescript": "^5.7.2" } } diff --git a/website/showcase.json b/website/showcase.json index 0690cba0e31..20b1e52dcd2 100644 --- a/website/showcase.json +++ b/website/showcase.json @@ -5,8 +5,15 @@ "icon": "facebook.webp", "linkAppStore": "https://apps.apple.com/app/facebook/id284882215", "linkPlayStore": "https://play.google.com/store/apps/details?id=com.facebook.katana", + "linkMetaQuest": "https://www.meta.com/experiences/facebook/7495711360547796/", "pinned": true }, + { + "name": "Instagram", + "icon": "instagram.png", + "linkMetaQuest": "https://www.meta.com/experiences/instagram/6894135610696226/", + "infoLink": "https://engineering.fb.com/2024/10/02/android/react-at-meta-connect-2024/" + }, { "name": "Facebook Ads Manager", "icon": "adsmanager.png", @@ -14,8 +21,8 @@ "linkPlayStore": "https://play.google.com/store/apps/details?id=com.facebook.adsmanager" }, { - "name": "Meta Quest", - "icon": "metaquest.png", + "name": "Meta Horizon", + "icon": "metahorizon.webp", "linkAppStore": "https://apps.apple.com/us/app/oculus/id1366478176", "linkPlayStore": "https://play.google.com/store/apps/details?id=com.oculus.twilight&hl=en_US", "pinned": true diff --git a/website/sidebars.json b/website/sidebars.json deleted file mode 100644 index fd9b21fe1ca..00000000000 --- a/website/sidebars.json +++ /dev/null @@ -1,296 +0,0 @@ -{ - "docs": { - "The Basics": [ - "getting-started", - "intro-react-native-components", - "intro-react", - "handling-text-input", - "using-a-scrollview", - "using-a-listview", - "troubleshooting", - "platform-specific-code", - "more-resources" - ], - "Environment setup": [ - "environment-setup", - "set-up-your-environment", - "integration-with-existing-apps", - "integration-with-android-fragment", - "building-for-tv", - "out-of-tree-platforms" - ], - "Workflow": [ - "running-on-device", - "fast-refresh", - "metro", - "libraries", - "typescript", - "upgrading" - ], - "UI & Interaction": [ - "style", - "height-and-width", - "flexbox", - "images", - "colors", - { - "type": "category", - "label": "Interaction", - "collapsible": false, - "collapsed": false, - "items": [ - "handling-touches", - "navigation", - "animations", - "gesture-responder-system" - ] - }, - { - "type": "category", - "label": "Connectivity", - "collapsible": false, - "collapsed": false, - "items": ["network", "security"] - }, - { - "type": "category", - "label": "Inclusion", - "collapsible": false, - "collapsed": false, - "items": ["accessibility"] - } - ], - "Debugging": [ - "debugging", - "react-native-devtools", - "debugging-native-code", - "debugging-release-builds", - "other-debugging-methods" - ], - "Testing": ["testing-overview"], - "Performance": [ - "performance", - "build-speed", - "optimizing-flatlist-configuration", - "optimizing-javascript-loading", - "profiling" - ], - "JavaScript Runtime": ["javascript-environment", "timers", "hermes"], - "Codegen": [ - "the-new-architecture/what-is-codegen", - "the-new-architecture/using-codegen", - "the-new-architecture/codegen-cli" - ], - "Native Development": [ - { - "type": "doc", - "id": "native-platform", - "label": "Introduction" - }, - { - "type": "category", - "label": "Modules", - "collapsible": false, - "collapsed": false, - "items": [ - { - "type": "doc", - "id": "turbo-native-modules-introduction", - "label": "Android and iOS" - }, - { - "type": "doc", - "id": "the-new-architecture/pure-cxx-modules", - "label": "Cross-Platform with C++" - }, - { - "type": "doc", - "id": "the-new-architecture/custom-cxx-types", - "label": "Advanced: Custom C++ Types" - } - ] - }, - { - "type": "category", - "label": "Components", - "collapsible": false, - "collapsed": false, - "items": [ - { - "type": "doc", - "id": "fabric-native-components-introduction", - "label": "Android & iOS" - } - ] - }, - { - "type": "category", - "label": "Miscellaneous", - "collapsible": true, - "collapsed": true, - "items": [ - { - "type": "doc", - "id": "appendix", - "label": "Appendix" - }, - { - "type": "doc", - "id": "the-new-architecture/create-module-library" - } - ] - } - ], - "Android and iOS guides": [ - { - "type": "category", - "label": "Android", - "collapsible": false, - "collapsed": false, - "items": [ - "headless-js-android", - "signed-apk-android", - "communication-android", - "react-native-gradle-plugin" - ] - }, - { - "type": "category", - "label": "iOS", - "collapsible": false, - "collapsed": false, - "items": [ - "linking-libraries-ios", - "running-on-simulator-ios", - "communication-ios", - "app-extensions", - "publishing-to-app-store" - ] - } - ], - "Legacy Architecture": [ - { - "type": "category", - "label": "Native Modules", - "collapsible": true, - "collapsed": true, - "items": [ - "legacy/native-modules-intro", - "legacy/native-modules-android", - "legacy/native-modules-ios", - "legacy/native-modules-setup", - "legacy/local-library-setup" - ] - }, - { - "type": "category", - "label": "Native Components", - "collapsible": true, - "collapsed": true, - "items": [ - "legacy/native-components-android", - "legacy/native-components-ios", - "legacy/direct-manipulation" - ] - } - ] - }, - "api": { - "APIs": [ - "accessibilityinfo", - "alert", - "animated", - "animatedvalue", - "animatedvaluexy", - "appearance", - "appregistry", - "appstate", - "devsettings", - "dimensions", - "easing", - "interactionmanager", - "keyboard", - "layoutanimation", - "linking", - "panresponder", - "pixelratio", - "platform", - "platformcolor", - "roottag", - "share", - "stylesheet", - "systrace", - "transforms", - "vibration", - { - "type": "category", - "label": "Hooks", - "collapsed": false, - "items": ["usecolorscheme", "usewindowdimensions"] - }, - { - "type": "category", - "label": "Android APIs", - "collapsed": false, - "items": ["backhandler", "permissionsandroid", "toastandroid"] - }, - { - "type": "category", - "label": "iOS APIs", - "collapsed": false, - "items": ["actionsheetios", "dynamiccolorios", "settings"] - } - ] - }, - "components": { - "Core Components": [ - "components-and-apis", - "activityindicator", - "button", - "flatlist", - "image", - "imagebackground", - "keyboardavoidingview", - "modal", - "pressable", - "refreshcontrol", - "scrollview", - "sectionlist", - "statusbar", - "switch", - "text", - "textinput", - "touchablehighlight", - "touchableopacity", - "touchablewithoutfeedback", - "view", - "virtualizedlist", - { - "type": "category", - "label": "Android Components", - "collapsed": false, - "items": ["drawerlayoutandroid", "touchablenativefeedback"] - }, - { - "type": "category", - "label": "iOS Components", - "collapsed": false, - "items": ["inputaccessoryview", "safeareaview"] - } - ], - "Props": [ - "image-style-props", - "layout-props", - "shadow-props", - "text-style-props", - "view-style-props" - ], - "Object Types": [ - "layoutevent", - "pressevent", - "react-node", - "rect", - "viewtoken" - ] - } -} diff --git a/website/sidebars.ts b/website/sidebars.ts new file mode 100644 index 00000000000..2ac73e5c991 --- /dev/null +++ b/website/sidebars.ts @@ -0,0 +1,308 @@ +import type {SidebarsConfig} from '@docusaurus/plugin-content-docs'; + +export default { + docs: { + 'The Basics': [ + 'getting-started', + 'intro-react-native-components', + 'intro-react', + 'handling-text-input', + 'using-a-scrollview', + 'using-a-listview', + 'troubleshooting', + 'platform-specific-code', + 'more-resources', + ], + 'Environment setup': [ + 'environment-setup', + 'set-up-your-environment', + 'integration-with-existing-apps', + 'integration-with-android-fragment', + 'building-for-tv', + 'out-of-tree-platforms', + ], + Workflow: [ + 'running-on-device', + 'fast-refresh', + 'metro', + 'libraries', + 'typescript', + 'upgrading', + ], + 'UI & Interaction': [ + 'style', + 'height-and-width', + 'flexbox', + 'images', + 'colors', + { + type: 'category', + label: 'Interaction', + collapsible: false, + collapsed: false, + items: [ + 'handling-touches', + 'navigation', + 'animations', + 'gesture-responder-system', + ], + }, + { + type: 'category', + label: 'Connectivity', + collapsible: false, + collapsed: false, + items: ['network', 'security'], + }, + { + type: 'category', + label: 'Inclusion', + collapsible: false, + collapsed: false, + items: ['accessibility'], + }, + ], + Debugging: [ + 'debugging', + 'react-native-devtools', + 'debugging-native-code', + 'debugging-release-builds', + 'other-debugging-methods', + ], + Testing: ['testing-overview'], + Performance: [ + 'performance', + 'build-speed', + 'optimizing-flatlist-configuration', + 'optimizing-javascript-loading', + 'profiling', + ], + 'JavaScript Runtime': ['javascript-environment', 'timers', 'hermes'], + Codegen: [ + 'the-new-architecture/what-is-codegen', + 'the-new-architecture/using-codegen', + 'the-new-architecture/codegen-cli', + ], + 'Native Development': [ + { + type: 'doc', + id: 'native-platform', + label: 'Introduction', + }, + { + type: 'category', + label: 'Modules', + collapsible: false, + collapsed: false, + items: [ + { + type: 'doc', + id: 'turbo-native-modules-introduction', + label: 'Android and iOS', + }, + { + type: 'doc', + id: 'the-new-architecture/pure-cxx-modules', + label: 'Cross-Platform with C++', + }, + { + type: 'doc', + id: 'the-new-architecture/custom-cxx-types', + label: 'Advanced: Custom C++ Types', + }, + ], + }, + { + type: 'category', + label: 'Components', + collapsible: false, + collapsed: false, + items: [ + { + type: 'doc', + id: 'fabric-native-components-introduction', + label: 'Android & iOS', + }, + { + type: 'doc', + id: 'the-new-architecture/direct-manipulation-new-architecture', + label: 'Direct Manipulation', + }, + { + type: 'doc', + id: 'the-new-architecture/layout-measurements', + label: 'Measuring the Layout', + }, + ], + }, + { + type: 'category', + label: 'Miscellaneous', + collapsible: true, + collapsed: true, + items: [ + { + type: 'doc', + id: 'appendix', + label: 'Appendix', + }, + { + type: 'doc', + id: 'the-new-architecture/create-module-library', + }, + ], + }, + ], + 'Android and iOS guides': [ + { + type: 'category', + label: 'Android', + collapsible: false, + collapsed: false, + items: [ + 'headless-js-android', + 'signed-apk-android', + 'communication-android', + 'react-native-gradle-plugin', + ], + }, + { + type: 'category', + label: 'iOS', + collapsible: false, + collapsed: false, + items: [ + 'linking-libraries-ios', + 'running-on-simulator-ios', + 'communication-ios', + 'app-extensions', + 'publishing-to-app-store', + ], + }, + ], + 'Legacy Architecture': [ + { + type: 'category', + label: 'Native Modules', + collapsible: true, + collapsed: true, + items: [ + 'legacy/native-modules-intro', + 'legacy/native-modules-android', + 'legacy/native-modules-ios', + 'legacy/native-modules-setup', + 'legacy/local-library-setup', + ], + }, + { + type: 'category', + label: 'Native Components', + collapsible: true, + collapsed: true, + items: [ + 'legacy/native-components-android', + 'legacy/native-components-ios', + 'legacy/direct-manipulation', + ], + }, + ], + }, + api: { + APIs: [ + 'accessibilityinfo', + 'alert', + 'animated', + 'animatedvalue', + 'animatedvaluexy', + 'appearance', + 'appregistry', + 'appstate', + 'devsettings', + 'dimensions', + 'easing', + 'interactionmanager', + 'keyboard', + 'layoutanimation', + 'linking', + 'panresponder', + 'pixelratio', + 'platform', + 'platformcolor', + 'roottag', + 'share', + 'stylesheet', + 'systrace', + 'transforms', + 'vibration', + { + type: 'category', + label: 'Hooks', + collapsed: false, + items: ['usecolorscheme', 'usewindowdimensions'], + }, + { + type: 'category', + label: 'Android APIs', + collapsed: false, + items: ['backhandler', 'permissionsandroid', 'toastandroid'], + }, + { + type: 'category', + label: 'iOS APIs', + collapsed: false, + items: ['actionsheetios', 'dynamiccolorios', 'settings'], + }, + ], + }, + components: { + 'Core Components': [ + 'components-and-apis', + 'activityindicator', + 'button', + 'flatlist', + 'image', + 'imagebackground', + 'keyboardavoidingview', + 'modal', + 'pressable', + 'refreshcontrol', + 'scrollview', + 'sectionlist', + 'statusbar', + 'switch', + 'text', + 'textinput', + 'touchablehighlight', + 'touchableopacity', + 'touchablewithoutfeedback', + 'view', + 'virtualizedlist', + { + type: 'category', + label: 'Android Components', + collapsed: false, + items: ['drawerlayoutandroid', 'touchablenativefeedback'], + }, + { + type: 'category', + label: 'iOS Components', + collapsed: false, + items: ['inputaccessoryview', 'safeareaview'], + }, + ], + Props: [ + 'image-style-props', + 'layout-props', + 'shadow-props', + 'text-style-props', + 'view-style-props', + ], + 'Object Types': [ + 'layoutevent', + 'pressevent', + 'react-node', + 'rect', + 'viewtoken', + ], + }, +} satisfies SidebarsConfig; diff --git a/website/sidebarsArchitecture.json b/website/sidebarsArchitecture.json deleted file mode 100644 index 0f6c3635b9c..00000000000 --- a/website/sidebarsArchitecture.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "architecture": [ - { - "type": "category", - "label": "Architecture", - "collapsed": false, - "items": [ - "architecture-overview", - "landing-page", - { - "type": "category", - "label": "Rendering", - "collapsible": false, - "collapsed": false, - "items": [ - "fabric-renderer", - "render-pipeline", - "xplat-implementation", - "view-flattening", - "threading-model" - ] - }, - { - "type": "category", - "label": "Build Tools", - "collapsible": false, - "collapsed": false, - "items": ["bundled-hermes"] - }, - "architecture-glossary" - ] - } - ] -} diff --git a/website/sidebarsArchitecture.ts b/website/sidebarsArchitecture.ts new file mode 100644 index 00000000000..54397f5493e --- /dev/null +++ b/website/sidebarsArchitecture.ts @@ -0,0 +1,36 @@ +import type {SidebarsConfig} from '@docusaurus/plugin-content-docs'; + +export default { + architecture: [ + { + type: 'category', + label: 'Architecture', + collapsed: false, + items: [ + 'architecture-overview', + 'landing-page', + { + type: 'category', + label: 'Rendering', + collapsible: false, + collapsed: false, + items: [ + 'fabric-renderer', + 'render-pipeline', + 'xplat-implementation', + 'view-flattening', + 'threading-model', + ], + }, + { + type: 'category', + label: 'Build Tools', + collapsible: false, + collapsed: false, + items: ['bundled-hermes'], + }, + 'architecture-glossary', + ], + }, + ], +} satisfies SidebarsConfig; diff --git a/website/sidebarsCommunity.json b/website/sidebarsCommunity.json deleted file mode 100644 index efb90034ecf..00000000000 --- a/website/sidebarsCommunity.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "community": [ - { - "type": "category", - "label": "Community", - "collapsed": false, - "collapsible": false, - "items": ["overview", "staying-updated", "communities", "support"] - } - ] -} diff --git a/website/sidebarsCommunity.ts b/website/sidebarsCommunity.ts new file mode 100644 index 00000000000..cbe83d78989 --- /dev/null +++ b/website/sidebarsCommunity.ts @@ -0,0 +1,13 @@ +import type {SidebarsConfig} from '@docusaurus/plugin-content-docs'; + +export default { + community: [ + { + type: 'category', + label: 'Community', + collapsed: false, + collapsible: false, + items: ['overview', 'staying-updated', 'communities', 'support'], + }, + ], +} satisfies SidebarsConfig; diff --git a/website/sidebarsContributing.json b/website/sidebarsContributing.json deleted file mode 100644 index 0cf4d7e9e4b..00000000000 --- a/website/sidebarsContributing.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "contributing": [ - { - "type": "category", - "label": "Contributing to React Native", - "collapsed": false, - "collapsible": true, - "items": [ - "overview", - "how-to-contribute-code", - "how-to-build-from-source", - "how-to-run-and-write-tests", - "how-to-open-a-pull-request", - "changelogs-in-pull-requests", - "how-to-file-an-issue", - "contribution-license-agreement", - { - "type": "category", - "label": "Managing repository", - "collapsed": false, - "collapsible": false, - "items": [ - "triaging-github-issues", - "labeling-github-issues", - "managing-pull-requests", - "bots-reference" - ] - } - ] - } - ] -} diff --git a/website/sidebarsContributing.ts b/website/sidebarsContributing.ts new file mode 100644 index 00000000000..64d430bfd78 --- /dev/null +++ b/website/sidebarsContributing.ts @@ -0,0 +1,34 @@ +import type {SidebarsConfig} from '@docusaurus/plugin-content-docs'; + +export default { + contributing: [ + { + type: 'category', + label: 'Contributing to React Native', + collapsed: false, + collapsible: true, + items: [ + 'overview', + 'how-to-contribute-code', + 'how-to-build-from-source', + 'how-to-run-and-write-tests', + 'how-to-open-a-pull-request', + 'changelogs-in-pull-requests', + 'how-to-file-an-issue', + 'contribution-license-agreement', + { + type: 'category', + label: 'Managing repository', + collapsed: false, + collapsible: false, + items: [ + 'triaging-github-issues', + 'labeling-github-issues', + 'managing-pull-requests', + 'bots-reference', + ], + }, + ], + }, + ], +} satisfies SidebarsConfig; diff --git a/website/src/css/customTheme.scss b/website/src/css/customTheme.scss index d252ba1b796..1c8fed54834 100644 --- a/website/src/css/customTheme.scss +++ b/website/src/css/customTheme.scss @@ -33,8 +33,6 @@ --ifm-table-head-color: var(--subtle); --ifm-link-hover-decoration: none; --ifm-navbar-background-color: var(--deepdark); - --ifm-transition-fast: 0; - --ifm-transition-slow: 0; --ifm-pre-line-height: 1.5; --ifm-tabs-padding-vertical: 6px; --ifm-color-warning: #ffe564; @@ -699,10 +697,6 @@ a[class*="tagRegular"] { transform: rotate(180deg) scale(0.9); } - .clean-btn:hover { - background: var(--ifm-color-emphasis-800); - } - .DocSearch-Button { border-radius: var(--ifm-global-radius); padding: 0 6px 0 10px; @@ -955,8 +949,6 @@ aside[class^="theme-doc-sidebar-container"] { .menu__list { margin-bottom: 8px; - transition: none !important; - height: auto !important; &.blog-menu__list { font-size: 14px; @@ -1048,12 +1040,6 @@ aside[class^="theme-doc-sidebar-container"] { } } -.menu__list-item.menu__list-item--collapsed { - .menu__list { - height: 0 !important; - } -} - .menu--responsive .menu__button { right: 1.3rem; bottom: 1.3rem; @@ -1156,7 +1142,9 @@ button[class*="tocCollapsibleButton"] { padding: 1.5rem !important; border: 1px solid var(--ifm-color-emphasis-300) !important; box-shadow: none !important; - transition: background-color 0.2s ease-in-out, border-color 0.2s ease-in-out !important; + transition: + background-color 0.2s ease-in-out, + border-color 0.2s ease-in-out !important; background-color: var(--ifm-background-color); &:hover { @@ -1322,6 +1310,12 @@ button[class*="tocCollapsibleButton"] { --docusaurus-announcement-bar-height: auto !important; } +@media (min-width: 997px) { + :root { + --docusaurus-announcement-bar-height: auto !important; + } +} + div[class*="announcementBar"][role="banner"] { border-bottom-color: var(--deepdark); diff --git a/website/src/css/index.scss b/website/src/css/index.scss index f2897416113..1aa25592a9c 100644 --- a/website/src/css/index.scss +++ b/website/src/css/index.scss @@ -447,7 +447,6 @@ stroke-opacity: 0; transform: scale(2.25, 1.33) rotate(0); opacity: 1; - transition: none; } .LogoAnimation.mobile .screen { diff --git a/website/src/pages/Home/CallToAction/index.js b/website/src/pages/Home/CallToAction/index.tsx similarity index 100% rename from website/src/pages/Home/CallToAction/index.js rename to website/src/pages/Home/CallToAction/index.tsx diff --git a/website/src/pages/Home/Community/index.js b/website/src/pages/Home/Community/index.tsx similarity index 100% rename from website/src/pages/Home/Community/index.js rename to website/src/pages/Home/Community/index.tsx diff --git a/website/src/pages/Home/Framework/index.js b/website/src/pages/Home/Framework/index.tsx similarity index 100% rename from website/src/pages/Home/Framework/index.js rename to website/src/pages/Home/Framework/index.tsx diff --git a/website/src/pages/Home/Hero/Devices.js b/website/src/pages/Home/Hero/Devices.tsx similarity index 100% rename from website/src/pages/Home/Hero/Devices.js rename to website/src/pages/Home/Hero/Devices.tsx diff --git a/website/src/pages/Home/Hero/FloorBackground.js b/website/src/pages/Home/Hero/FloorBackground.tsx similarity index 100% rename from website/src/pages/Home/Hero/FloorBackground.js rename to website/src/pages/Home/Hero/FloorBackground.tsx diff --git a/website/src/pages/Home/Hero/GridBackground.js b/website/src/pages/Home/Hero/GridBackground.tsx similarity index 100% rename from website/src/pages/Home/Hero/GridBackground.js rename to website/src/pages/Home/Hero/GridBackground.tsx diff --git a/website/src/pages/Home/Hero/index.js b/website/src/pages/Home/Hero/index.tsx similarity index 100% rename from website/src/pages/Home/Hero/index.js rename to website/src/pages/Home/Hero/index.tsx diff --git a/website/src/pages/Home/Logo.js b/website/src/pages/Home/Logo.tsx similarity index 100% rename from website/src/pages/Home/Logo.js rename to website/src/pages/Home/Logo.tsx diff --git a/website/src/pages/Home/Native/index.js b/website/src/pages/Home/Native/index.tsx similarity index 100% rename from website/src/pages/Home/Native/index.js rename to website/src/pages/Home/Native/index.tsx diff --git a/website/src/pages/Home/Platforms/FoxFact.js b/website/src/pages/Home/Platforms/FoxFact.tsx similarity index 100% rename from website/src/pages/Home/Platforms/FoxFact.js rename to website/src/pages/Home/Platforms/FoxFact.tsx diff --git a/website/src/pages/Home/Platforms/index.js b/website/src/pages/Home/Platforms/index.tsx similarity index 100% rename from website/src/pages/Home/Platforms/index.js rename to website/src/pages/Home/Platforms/index.tsx diff --git a/website/src/pages/Home/Watch/index.js b/website/src/pages/Home/Watch/index.tsx similarity index 100% rename from website/src/pages/Home/Watch/index.js rename to website/src/pages/Home/Watch/index.tsx diff --git a/website/src/pages/Home/components/Section/index.js b/website/src/pages/Home/components/Section/index.tsx similarity index 100% rename from website/src/pages/Home/components/Section/index.js rename to website/src/pages/Home/components/Section/index.tsx diff --git a/website/src/pages/Home/components/SectionTitle/index.js b/website/src/pages/Home/components/SectionTitle/index.tsx similarity index 66% rename from website/src/pages/Home/components/SectionTitle/index.js rename to website/src/pages/Home/components/SectionTitle/index.tsx index a629d9b064b..e0f3c96d7e6 100644 --- a/website/src/pages/Home/components/SectionTitle/index.js +++ b/website/src/pages/Home/components/SectionTitle/index.tsx @@ -9,11 +9,19 @@ import React from 'react'; import styles from './styles.module.css'; -function SectionTitle({title, description}) { +function SectionTitle({ + title, + description, +}: { + title: string; + description?: React.ReactNode; +}) { return (

{title}

-

{description}

+ {description ? ( +

{description}

+ ) : null}
); } diff --git a/website/src/pages/Home/components/ThemeImage/index.js b/website/src/pages/Home/components/ThemeImage/index.tsx similarity index 90% rename from website/src/pages/Home/components/ThemeImage/index.js rename to website/src/pages/Home/components/ThemeImage/index.tsx index 9988b8aa63f..1b50f92d5af 100644 --- a/website/src/pages/Home/components/ThemeImage/index.js +++ b/website/src/pages/Home/components/ThemeImage/index.tsx @@ -15,7 +15,8 @@ function ThemeImage({lightSrc, darkSrc, className, alt}) { mutations.forEach(mutation => { if ( mutation.type === 'attributes' && - mutation.attributeName === 'data-theme' + mutation.attributeName === 'data-theme' && + mutation.target instanceof Element ) { setTheme(mutation.target.getAttribute('data-theme')); } diff --git a/website/src/pages/Home/index.js b/website/src/pages/Home/index.tsx similarity index 100% rename from website/src/pages/Home/index.js rename to website/src/pages/Home/index.tsx diff --git a/website/src/pages/index.js b/website/src/pages/index.tsx similarity index 100% rename from website/src/pages/index.js rename to website/src/pages/index.tsx diff --git a/website/src/pages/showcase.js b/website/src/pages/showcase.tsx similarity index 94% rename from website/src/pages/showcase.js rename to website/src/pages/showcase.tsx index ae443c0963e..c7c102b5b25 100644 --- a/website/src/pages/showcase.js +++ b/website/src/pages/showcase.tsx @@ -9,29 +9,19 @@ import React, {useEffect, useState} from 'react'; import useBaseUrl from '@docusaurus/useBaseUrl'; import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; import Layout from '@theme/Layout'; -import ThemedImage from '@theme/ThemedImage'; - +import type users from '../../showcase.json'; import IconExternalLink from '../theme/Icon/ExternalLink'; +import ThemedImage from '@theme/ThemedImage'; const renderApp = (app, i) => ; function Section({ - element = 'section', children, - className, background = 'light', -}) { - const El = element; - return ( - - {children} - - ); +}: React.PropsWithChildren<{ + background?: 'light' | 'dark'; +}>) { + return
{children}
; } const AppBox = ({app}) => { @@ -66,10 +56,6 @@ const AppBox = ({app}) => { }; const renderLinks = app => { - if (!app.linkAppStore && !app.linkPlayStore && !app.linkDesktop) { - return

; - } - const links = [ app.linkAppStore ? ( @@ -86,12 +72,21 @@ const renderLinks = app => { Desktop ) : null, + app.linkMetaQuest ? ( + + Meta Quest + + ) : null, ] .filter(Boolean) .flatMap((link, i) => i === 0 ? [link] : [, link] ); + if (links.length === 0) { + return

; + } + return

{links}

; }; @@ -100,9 +95,8 @@ const randomizeApps = apps => const Showcase = () => { const {siteConfig} = useDocusaurusContext(); - - const {meta, microsoft, shopify, wix, amazon, others} = - siteConfig.customFields.users; + const {meta, microsoft, shopify, wix, amazon, others} = siteConfig + .customFields.users as typeof users; const [pinnedRandomizedApps, setPinnedRandomizedApps] = useState([]); const [randomizedApps, setRandomizedApps] = useState([]); diff --git a/website/src/pages/versions.js b/website/src/pages/versions.tsx similarity index 95% rename from website/src/pages/versions.js rename to website/src/pages/versions.tsx index 6e5030cc990..7eed7e3dc90 100644 --- a/website/src/pages/versions.js +++ b/website/src/pages/versions.tsx @@ -8,11 +8,19 @@ import React from 'react'; import Layout from '@theme/Layout'; import useBaseUrl from '@docusaurus/useBaseUrl'; -const versions = require('../../versions.json'); +import versions from '../../versions.json'; // The versionsArchived mapping is a custom feature, NOT a Docusaurus feature -const versionsArchived = require('../../versionsArchived.json'); +import versionsArchived from '../../versionsArchived.json'; -const VersionItem = ({version, archivedDocumentationUrl, currentVersion}) => { +const VersionItem = ({ + version, + archivedDocumentationUrl, + currentVersion, +}: { + version: string; + currentVersion: string; + archivedDocumentationUrl?: string; +}) => { const versionName = version === 'next' ? 'main' : version; const isCurrentVersion = currentVersion === version; diff --git a/website/src/theme/Badge/index.js b/website/src/theme/Badge/index.tsx similarity index 100% rename from website/src/theme/Badge/index.js rename to website/src/theme/Badge/index.tsx diff --git a/website/src/theme/Blog/Components/Author/index.js b/website/src/theme/Blog/Components/Author/index.tsx similarity index 99% rename from website/src/theme/Blog/Components/Author/index.js rename to website/src/theme/Blog/Components/Author/index.tsx index 7c9e4ae18be..8c550c24da2 100644 --- a/website/src/theme/Blog/Components/Author/index.js +++ b/website/src/theme/Blog/Components/Author/index.tsx @@ -4,6 +4,7 @@ import Link from '@docusaurus/Link'; import AuthorSocials from '@theme/Blog/Components/Author/Socials'; import Heading from '@theme/Heading'; import styles from './styles.module.css'; + function MaybeLink(props) { if (props.href) { return ; diff --git a/website/src/theme/BlogSidebar/Desktop/index.d.ts b/website/src/theme/BlogSidebar/Desktop/index.d.ts deleted file mode 100644 index 261cea9e351..00000000000 --- a/website/src/theme/BlogSidebar/Desktop/index.d.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ -/// -import type { Props } from "@theme/BlogSidebar/Desktop"; -export default function BlogSidebarDesktop({ sidebar }: Props): JSX.Element; diff --git a/website/src/theme/BlogSidebar/Desktop/index.js b/website/src/theme/BlogSidebar/Desktop/index.tsx similarity index 93% rename from website/src/theme/BlogSidebar/Desktop/index.js rename to website/src/theme/BlogSidebar/Desktop/index.tsx index 5616e848a37..deef488f67d 100644 --- a/website/src/theme/BlogSidebar/Desktop/index.js +++ b/website/src/theme/BlogSidebar/Desktop/index.tsx @@ -10,8 +10,9 @@ import clsx from 'clsx'; import Link from '@docusaurus/Link'; import {translate} from '@docusaurus/Translate'; import styles from './styles.module.css'; +import type {Props} from '@theme/BlogSidebar/Desktop'; -export default function BlogSidebarDesktop({sidebar}) { +export default function BlogSidebarDesktop({sidebar}: Props) { let cachedYear = null; return (