diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..65365be --- /dev/null +++ b/.editorconfig @@ -0,0 +1,15 @@ +# EditorConfig helps developers define and maintain consistent +# coding styles between different editors and IDEs +# editorconfig.org + +root = true + +[*] + +indent_style = space +indent_size = 2 + +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..e27f70f --- /dev/null +++ b/.gitattributes @@ -0,0 +1,3 @@ +*.pbxproj -text +# specific for windows script files +*.bat text eol=crlf diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..b1ea67d --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,32 @@ +name: Release to NPM + +on: + release: + types: [published] + +jobs: + publish: + runs-on: ubuntu-latest + + steps: + - name: Checkout repo + uses: actions/checkout@v6 + + - name: Setup Node.js + uses: actions/setup-node@v6 + with: + node-version: '22' + cache: 'npm' + registry-url: 'https://registry.npmjs.org/' + + - name: Install dependencies + run: npm ci + + - name: Build package + run: | + if node -e "process.exit(require('./package.json').scripts?.build ? 0 : 1)"; then npm run build; fi + + - name: Publish to NPM + run: npm run release + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml new file mode 100644 index 0000000..b555363 --- /dev/null +++ b/.github/workflows/validate.yml @@ -0,0 +1,36 @@ +name: Validate + +on: + pull_request: + branches: [main, master, development] + push: + branches: [main, master, development] + +jobs: + validate: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v6 + + - name: Setup Node.js + uses: actions/setup-node@v6 + with: + node-version: '22' + cache: 'npm' + + - name: Install dependencies + run: npm ci + + - name: Run linting + run: | + if node -e "process.exit(require('./package.json').scripts?.lint ? 0 : 1)"; then npm run lint; fi + + - name: Run tests + run: | + if node -e "process.exit(require('./package.json').scripts?.test ? 0 : 1)"; then npm test; fi + + - name: Run build + run: | + if node -e "process.exit(require('./package.json').scripts?.build ? 0 : 1)"; then npm run build; fi diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..99a1074 --- /dev/null +++ b/.gitignore @@ -0,0 +1,78 @@ +# OSX +# +.DS_Store + +# XDE +.expo/ + +# VSCode +.vscode/ +jsconfig.json + +# Xcode +# +build/ +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 +xcuserdata +*.xccheckout +*.moved-aside +DerivedData +*.hmap +*.ipa +*.xcuserstate +project.xcworkspace +**/.xcode.env.local + +# Android/IJ +# +.classpath +.cxx +.gradle +.idea +.project +.settings +local.properties +android.iml + +# Cocoapods +# +example/ios/Pods + +# Ruby +example/vendor/ + +# node.js +# +node_modules/ +npm-debug.log +yarn-debug.log +yarn-error.log + +# BUCK +buck-out/ +\.buckd/ +android/app/libs +android/keystores/debug.keystore + +# Expo +.expo/ + +# Turborepo +.turbo/ + +# generated by bob +lib/ + +# React Native Codegen +ios/generated +android/generated + +# React Native Nitro Modules +nitrogen/ diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 0000000..c004e35 --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +v22.20.0 diff --git a/.prettierrc.js b/.prettierrc.js new file mode 100644 index 0000000..2d1d6c0 --- /dev/null +++ b/.prettierrc.js @@ -0,0 +1,10 @@ +module.exports = { + printWidth: 120, + arrowParens: 'always', + tabWidth: 2, + semi: true, + bracketSameLine: true, + jsxSingleQuote: true, + singleQuote: true, + useTabs: false, +}; diff --git a/.watchmanconfig b/.watchmanconfig new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/.watchmanconfig @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..9b5ef46 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,127 @@ +# Contributing + +This document provides guidelines for contributing to this project. + +## Development + +### Prerequisites + +- Node.js 22+ +- npm +- For iOS: Xcode + CocoaPods (`gem install cocoapods`) +- For Android: Android Studio + JDK 17+ + +### Example app + +An example React Native application lives in the `example` directory. It demonstrates the component in action and serves as a testing ground during development. + +Run the Metro bundler from the repo root: + +```sh +npm run example +``` + +Then launch the app on your target platform from the `example` directory: + +```sh +# iOS +cd example && npx react-native run-ios + +# Android +cd example && npx react-native run-android +``` + +For iOS, install CocoaPods first: + +```sh +cd example/ios && bundle exec pod install +``` + +### Local development + +1. **Clone and install dependencies** + - Clone the repo and navigate to the project directory + - Run `npm install` to install all dependencies + + ```sh + git clone https://github.com/RonasIT/react-native-controlled-input.git + cd react-native-controlled-input + npm install + ``` + +2. **Make changes** + - Edit source files under `src/` + - For native changes, edit files under `ios/` or `android/` + +3. **Test your changes** + - Run `npm run lint` to type-check (`tsc`) and lint the codebase (`eslint`) + - Verify your changes work end-to-end in the example app + +4. **Submit changes** + - Create a pull request with your modifications + - Include clear descriptions of changes + - Reference any related issues or discussions + +## Build + +Build the JS output (outputs to `lib/`): + +```sh +npm run build +``` + +This runs `react-native-builder-bob` and produces ESM + TypeScript declaration files. + +To clean build artifacts: + +```sh +npm run clean +``` + +## Repository guidelines + +### Branch naming + +Use descriptive branch names and follow [Conventional Branch](https://conventional-branch.github.io/) guidelines. + +### Commit messages + +Follow the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) format + +### Code checks + +Repository has pre-commit code style and correctness checks. You can run them manually using `lint` and `format` scripts. + +### Pull request process + +1. **Create a feature branch** from `main` +2. **Make your changes** following the coding standards +3. **Test your changes** thoroughly +4. **Update documentation** if needed +5. **Submit a pull request** with a clear description + +## Releases + +To create a new release: + +1. **Bump the version**: In the `plugin` directory run `npm version {patch|minor|major}` to update the version number in `package.json` and create a git commit and tag + - `patch`: Bug fixes (0.2.0 → 0.2.1) + - `minor`: New features (0.2.0 → 0.3.0) + - `major`: Breaking changes (0.2.0 → 1.0.0) + +2. **Push changes**: Create commit, tag and push them to the repository: + + ```bash + git commit -m "chore: release v0.18.0" + git push && git push --tags + ``` + +3. **Create GitHub release**: Go to the [GitHub Releases](../../releases) page and: + - Click "Create a new release" + - Select the tag created in step 1 + - Add release notes describing the changes + - Click "Publish release" + +4. **Automatic NPM publication**: Once the GitHub release is published, the package will be automatically published to NPM via GitHub Actions workflow. + +> **Note**: Make sure you have the `NPM_TOKEN` secret configured in your repository settings for the NPM publication to work. diff --git a/ControlledInput.podspec b/ControlledInput.podspec new file mode 100644 index 0000000..055b2ab --- /dev/null +++ b/ControlledInput.podspec @@ -0,0 +1,20 @@ +require "json" + +package = JSON.parse(File.read(File.join(__dir__, "package.json"))) + +Pod::Spec.new do |s| + s.name = "ControlledInput" + s.version = package["version"] + s.summary = package["description"] + s.homepage = package["homepage"] + s.license = package["license"] + s.authors = package["author"] + + s.platforms = { :ios => min_ios_version_supported } + s.source = { :git => "https://github.com/RonasIT/react-native-controlled-input.git", :tag => "#{s.version}" } + + s.source_files = "ios/**/*.{h,m,mm,swift,cpp}" + s.private_header_files = "ios/**/*.h" + + install_modules_dependencies(s) +end diff --git a/README.md b/README.md index 84ce91a..394c62b 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,129 @@ -# react-native-controlled-input -React Native Controlled Input +# @ronas-it/react-native-controlled-input + +A controlled React Native input that lets you format and constrain the value exactly how you want in JS, while keeping the displayed text in sync without invalid characters flashing in the field. + +**`ControlledInputView`** (left) vs React Native **`TextInput`** (right), same JS formatting: with `TextInput`, rejected characters and intermediate states often flash until the filtered `value` is applied. + +### Promo / invite code (ABCD-1234) + +| ControlledInputView | TextInput | +| :-----------------: | :-------: | +| ControlledInputView promo code | TextInput promo code | + +### Card expiry (MM/YY) + +| ControlledInputView | TextInput | +| :-----------------: | :-------: | +| ControlledInputView date | TextInput date | + +## Problem + +With a regular controlled `TextInput`, native input is applied first, then JS receives the change, filters it, and sends the next `value` back. + +That means invalid characters can still flash in the field for a moment. + +`@ronas-it/react-native-controlled-input` is built for this exact case: you decide what text is valid, and the displayed value stays driven by `value`. + + +## Install + +```sh +npm install @ronas-it/react-native-controlled-input +``` + +Requires React Native New Architecture / Fabric. + +Compatible with [`react-native-keyboard-controller`](https://github.com/kirillzyusko/react-native-keyboard-controller). + +## Example + +```tsx +import { useRef, useState } from 'react'; +import { StyleSheet } from 'react-native'; +import { + ControlledInputView, + type ControlledInputViewRef, +} from '@ronas-it/react-native-controlled-input'; + +export function Example() { + const [value, setValue] = useState(''); + const inputRef = useRef(null); + + return ( + setValue(text.replace(/\d/g, ''))} + style={styles.input} + onFocus={() => {}} + onBlur={() => {}} + /> + ); +} + +const styles = StyleSheet.create({ + input: { + height: 48, + borderWidth: 1, + borderColor: '#ccc', + borderRadius: 8, + paddingHorizontal: 12, + fontSize: 16, + color: '#111', + }, +}); +``` + +```tsx +inputRef.current?.focus(); +inputRef.current?.blur(); +``` + +## Props + +| Prop | Type | Description | +|------|------|-------------| +| `value` | `string` | Current input value. | +| `onChangeText` | `(value: string) => void` | Called with the next text value. Filter it and update `value`. | +| `onFocus` | `() => void` | Called when the text input is focused. | +| `onBlur` | `() => void` | Called when the text input is blurred. | +| `onSubmitEditing` | `() => void` | Called when the text input is blurred. | +| `autoComplete` | `string` | Specifies autocomplete hints for the system. Same as React Native [`TextInput`](https://reactnative.dev/docs/textinput#autocomplete). | +| `autoCapitalize` | `string` | Can be `none`, `sentences`, `words`, `characters`. Same as React Native [`TextInput`](https://reactnative.dev/docs/textinput#autocapitalize). | +| `autoCorrect` | `boolean` (default `true`) | Toggles auto-correct. Same as React Native [`TextInput`](https://reactnative.dev/docs/textinput#autocorrect). | +| `keyboardType` | `string` | Determines which keyboard to open, e.g. `numeric`. Same as React Native [`TextInput`](https://reactnative.dev/docs/textinput#keyboardtype). | +| `returnKeyType` | `string` | Determines how the return key should look. Same as React Native [`TextInput`](https://reactnative.dev/docs/textinput#returnkeytype). | +| `placeholder` | `string` | The string that will be rendered before text input has been entered. | +| `placeholderTextColor` | `ColorValue` | The text color of the placeholder string. | +| `selectionColor` | `ColorValue` | The highlight and cursor color of the text input. | + +## Style support + +The same `style` API is supported on both iOS and Android. + +Commonly used supported styles: + +- `color`, `fontSize`, `fontFamily` +- `padding`, `paddingVertical`, `paddingHorizontal` +- `paddingTop`, `paddingBottom`, `paddingLeft`, `paddingRight`, `paddingStart`, `paddingEnd` +- `borderWidth`, `borderRadius`, `borderColor`, `backgroundColor` +- layout styles like `width`, `height`, `margin`, `flex` + +Implementation differs internally between platforms, but usage is the same for library consumers. + +## Fonts + +In Expo projects, **`fontFamily` on this input only applies when the font is linked for native use**. Relying on runtime loading alone (`useFonts` / `loadAsync`) is often not enough here; use the **expo-font config plugin** so fonts are embedded at build time. See [Expo Font — Configuration in app config](https://docs.expo.dev/versions/latest/sdk/font/#configuration-in-app-config). + +## Ref + +- `focus()` +- `blur()` + +## License + +MIT + +--- + +Made with [create-react-native-library](https://github.com/callstack/react-native-builder-bob) diff --git a/android/build.gradle b/android/build.gradle new file mode 100644 index 0000000..45d192b --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,94 @@ +buildscript { + ext.getExtOrDefault = {name -> + return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties['ControlledInput__' + name] + } + + repositories { + google() + mavenCentral() + } + + dependencies { + classpath "com.android.tools.build:gradle:8.7.2" + // noinspection DifferentKotlinGradleVersion + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${getExtOrDefault('kotlinVersion')}" + classpath "org.jetbrains.kotlin.plugin.compose:org.jetbrains.kotlin.plugin.compose.gradle.plugin:${getExtOrDefault('kotlinVersion')}" + } +} + + +apply plugin: "com.android.library" +apply plugin: "kotlin-android" +apply plugin: "org.jetbrains.kotlin.plugin.compose" + +apply plugin: "com.facebook.react" + +def getExtOrIntegerDefault(name) { + return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties["ControlledInput__" + name]).toInteger() +} + +android { + namespace "com.controlledinput" + + compileSdkVersion getExtOrIntegerDefault("compileSdkVersion") + + defaultConfig { + minSdkVersion getExtOrIntegerDefault("minSdkVersion") + targetSdkVersion getExtOrIntegerDefault("targetSdkVersion") + } + + buildFeatures { + buildConfig true + compose true + } + + buildTypes { + release { + minifyEnabled false + } + } + + lintOptions { + disable "GradleCompatible" + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + sourceSets { + main { + java.srcDirs += [ + "generated/java", + "generated/jni" + ] + } + } +} + +repositories { + mavenCentral() + google() +} + +def kotlin_version = getExtOrDefault("kotlinVersion") + +dependencies { + implementation "com.facebook.react:react-android" + implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" + + // Material Components (for BottomSheetDialog) + implementation 'com.google.android.material:material:1.13.0' + + // Jetpack Compose dependencies + def composeBom = platform('androidx.compose:compose-bom:2025.12.01') + implementation composeBom + implementation 'androidx.compose.ui:ui' + implementation 'androidx.compose.ui:ui-tooling-preview' + implementation 'androidx.compose.material3:material3' + implementation 'androidx.activity:activity-compose:1.12.2' + implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.8.7' + implementation 'androidx.savedstate:savedstate-ktx:1.2.1' + debugImplementation 'androidx.compose.ui:ui-tooling' +} diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..7d73b9d --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,5 @@ +ControlledInput_kotlinVersion=2.0.21 +ControlledInput_minSdkVersion=24 +ControlledInput_targetSdkVersion=34 +ControlledInput_compileSdkVersion=35 +ControlledInput_ndkVersion=27.1.12297006 diff --git a/android/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml new file mode 100644 index 0000000..a2f47b6 --- /dev/null +++ b/android/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + + diff --git a/android/src/main/java/com/controlledinput/ControlledInputPackage.kt b/android/src/main/java/com/controlledinput/ControlledInputPackage.kt new file mode 100644 index 0000000..db9b932 --- /dev/null +++ b/android/src/main/java/com/controlledinput/ControlledInputPackage.kt @@ -0,0 +1,19 @@ +package com.controlledinput; + +import com.facebook.react.ReactPackage +import com.facebook.react.bridge.NativeModule +import com.facebook.react.bridge.ReactApplicationContext +import com.facebook.react.uimanager.ViewManager +import java.util.ArrayList + +class ControlledInputViewPackage : ReactPackage { + override fun createViewManagers(reactContext: ReactApplicationContext): List> { + val viewManagers: MutableList> = ArrayList() + viewManagers.add(ControlledInputViewManager()) + return viewManagers + } + + override fun createNativeModules(reactContext: ReactApplicationContext): List { + return emptyList() + } +} diff --git a/android/src/main/java/com/controlledinput/ControlledInputView.kt b/android/src/main/java/com/controlledinput/ControlledInputView.kt new file mode 100644 index 0000000..05619e7 --- /dev/null +++ b/android/src/main/java/com/controlledinput/ControlledInputView.kt @@ -0,0 +1,401 @@ +package com.controlledinput + +import android.content.Context +import android.util.AttributeSet +import android.util.TypedValue +import android.view.View +import android.view.inputmethod.InputMethodManager +import android.widget.EditText +import android.widget.LinearLayout +import androidx.annotation.UiThread +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember +import androidx.compose.ui.focus.FocusRequester +import androidx.compose.ui.platform.ComposeView +import androidx.compose.ui.platform.LocalFocusManager +import androidx.compose.ui.platform.ViewCompositionStrategy +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.LifecycleRegistry +import androidx.lifecycle.findViewTreeLifecycleOwner +import androidx.lifecycle.setViewTreeLifecycleOwner +import androidx.savedstate.SavedStateRegistryOwner +import androidx.savedstate.setViewTreeSavedStateRegistryOwner +import com.facebook.react.bridge.ReactContext +import com.facebook.react.uimanager.UIManagerHelper +import com.facebook.react.uimanager.events.Event +import kotlinx.coroutines.flow.MutableStateFlow + +/** + * - [shouldUseAndroidLayout]: requestLayout posts measureAndLayout + * - onMeasure skips child [ComposeView] until attached (window + WindowRecomposer) + */ +class ControlledInputView : LinearLayout, LifecycleOwner { + constructor(context: Context) : super(context) { + configureComponent(context) + } + + constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) { + configureComponent(context) + } + + constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super( + context, + attrs, + defStyleAttr + ) { + configureComponent(context) + } + + private val lifecycleRegistry = LifecycleRegistry(this) + override val lifecycle: Lifecycle get() = lifecycleRegistry + + internal lateinit var viewModel: JetpackComposeViewModel + private val blurSignal = MutableStateFlow(0) + private val focusSignal = MutableStateFlow(0) + private lateinit var composeView: ComposeView + private var usesLocalFallbackLifecycle = false + private var windowLifecycleBound = false + + /** + * Hidden [EditText] used only as [FocusedInputObserver.lastFocusedInput] from + * https://github.com/kirillzyusko/react-native-keyboard-controller; [syncUpLayout] reads + * [EditText]-scoped geometry. It is NOT focused and does not participate in the focus + * chain — we push state via reflection + synthetic selection events instead. + */ + private val kbcLayoutHost: EditText by lazy { + EditText(context).also { v -> + v.layoutParams = LayoutParams(0, 0) + v.alpha = 0f + v.isFocusable = false + v.isFocusableInTouchMode = false + v.showSoftInputOnFocus = false + v.isClickable = false + v.isCursorVisible = false + v.isLongClickable = false + } + } + + /** + * EdgeToEdgeViewRegistry → KeyboardAnimationCallback + FocusedInputObserver + * (https://github.com/kirillzyusko/react-native-keyboard-controller). + * Null if that library is missing or not initialized. + */ + private fun resolveKbcCallbackAndObserver(): Pair? { + try { + val registryClass = + Class.forName("com.reactnativekeyboardcontroller.views.EdgeToEdgeViewRegistry") + val registryInstance = registryClass.getField("INSTANCE").get(null) + val edgeToEdgeView = + registryClass.getDeclaredMethod("get").invoke(registryInstance) ?: return null + + val callbackField = + edgeToEdgeView.javaClass.declaredFields.firstOrNull { + it.type.simpleName == "KeyboardAnimationCallback" + } ?: return null + callbackField.isAccessible = true + val callback = callbackField.get(edgeToEdgeView) ?: return null + + val observerField = + callback.javaClass.declaredFields.firstOrNull { + it.type.simpleName == "FocusedInputObserver" + } ?: return null + observerField.isAccessible = true + val observer = observerField.get(callback) ?: return null + return Pair(callback, observer) + } catch (_: ClassNotFoundException) { + return null + } catch (_: Exception) { + return null + } + } + + private fun setKbcViewTagFocused(callback: Any) { + try { + val f = callback.javaClass.getDeclaredField("viewTagFocused") + f.isAccessible = true + f.setInt(callback, id) + } catch (_: Exception) { + } + } + + private fun setKbcFocusedInputHolder() { + try { + val holderClass = + Class.forName("com.reactnativekeyboardcontroller.traversal.FocusedInputHolder") + val instance = holderClass.getField("INSTANCE").get(null) + holderClass + .getMethod("set", EditText::class.java) + .invoke(instance, kbcLayoutHost) + } catch (_: Exception) { + } + } + + /** + * `selection.end.y` for https://github.com/kirillzyusko/react-native-keyboard-controller / JS + * customHeight: prefer explicit style height (dp, same as padding in [InputStyle]), else measured + * view height in dp. + */ + private fun approximateSelectionEndYDp(): Double { + viewModel.inputStyle.value?.height?.takeIf { it > 0 }?.let { return it } + val dm = resources.displayMetrics + if (height > 0) { + return (height / dm.density).toDouble() + } + return 12.0 + } + + private fun dispatchSyntheticKbcSelectionEvent(observer: Any) { + val reactContext = context as? ReactContext ?: return + try { + val epField = observer.javaClass.getDeclaredField("eventPropagationView") + epField.isAccessible = true + val propagationId = (epField.get(observer) as View).id + + val surfaceId = UIManagerHelper.getSurfaceId(this) + val targetId = id + val endY = approximateSelectionEndYDp() + + val dataClz = + Class.forName("com.reactnativekeyboardcontroller.events.FocusedInputSelectionChangedEventData") + val dataCtor = + dataClz.declaredConstructors.singleOrNull { it.parameterTypes.size == 7 } ?: return + dataCtor.isAccessible = true + val data = + dataCtor.newInstance(targetId, 0.0, 0.0, 0.0, endY, 0, 0) + + val eventClz = + Class.forName("com.reactnativekeyboardcontroller.events.FocusedInputSelectionChangedEvent") + val eventCtor = + eventClz.getConstructor( + Int::class.javaPrimitiveType, + Int::class.javaPrimitiveType, + dataClz, + ) + val event = eventCtor.newInstance(surfaceId, propagationId, data) as Event<*> + + UIManagerHelper.getEventDispatcherForReactTag(reactContext, propagationId) + ?.dispatchEvent(event) + } catch (_: Exception) { + } + } + + /** + * Pushes ControlledInput state into https://github.com/kirillzyusko/react-native-keyboard-controller + * without stealing Compose focus: viewTagFocused, lastFocusedInput, FocusedInputHolder, + * syncUpLayout, synthetic selection. + */ + private fun syncKeyboardControllerFocusedInput() { + kbcLayoutHost.id = id + viewModel.inputStyle.value?.fontSize?.toFloat()?.let { + kbcLayoutHost.setTextSize(TypedValue.COMPLEX_UNIT_SP, it) + } + + val (callback, observer) = resolveKbcCallbackAndObserver() ?: return + + setKbcViewTagFocused(callback) + setKbcFocusedInputHolder() + + try { + val lastFocusedField = observer.javaClass.getDeclaredField("lastFocusedInput") + lastFocusedField.isAccessible = true + lastFocusedField.set(observer, kbcLayoutHost) + + val syncMethod = observer.javaClass.getDeclaredMethod("syncUpLayout") + syncMethod.isAccessible = true + syncMethod.invoke(observer) + + dispatchSyntheticKbcSelectionEvent(observer) + } catch (_: Exception) { + } + } + + private val shouldUseAndroidLayout = true + + override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) { + super.onLayout(changed, l, t, r, b) + kbcLayoutHost.layout(0, 0, width, height) + } + + override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { + if (shouldUseAndroidLayout && !isAttachedToWindow) { + setMeasuredDimension( + MeasureSpec.getSize(widthMeasureSpec).coerceAtLeast(0), + MeasureSpec.getSize(heightMeasureSpec).coerceAtLeast(0) + ) + return + } + super.onMeasure(widthMeasureSpec, heightMeasureSpec) + } + + override fun requestLayout() { + super.requestLayout() + if (shouldUseAndroidLayout) { + post { measureAndLayout() } + } + } + + @UiThread + private fun measureAndLayout() { + measure( + MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY) + ) + layout(left, top, right, bottom) + } + + override fun onAttachedToWindow() { + super.onAttachedToWindow() + bindComposeToWindowLifecycle() + } + + override fun onDetachedFromWindow() { + if (usesLocalFallbackLifecycle) { + lifecycleRegistry.currentState = Lifecycle.State.CREATED + } + super.onDetachedFromWindow() + } + + private fun bindComposeToWindowLifecycle() { + if (windowLifecycleBound) { + return + } + windowLifecycleBound = true + + val activity = (context as? ReactContext)?.currentActivity + val activityOwner = activity as? LifecycleOwner + if (activityOwner != null) { + usesLocalFallbackLifecycle = false + composeView.setViewTreeLifecycleOwner(activityOwner) + val savedStateOwner = activity as? SavedStateRegistryOwner + if (savedStateOwner != null) { + composeView.setViewTreeSavedStateRegistryOwner(savedStateOwner) + } + } else { + findViewTreeLifecycleOwnerFromAncestors()?.let { parentOwner -> + usesLocalFallbackLifecycle = false + composeView.setViewTreeLifecycleOwner(parentOwner) + } ?: run { + usesLocalFallbackLifecycle = true + composeView.setViewTreeLifecycleOwner(this) + lifecycleRegistry.currentState = Lifecycle.State.RESUMED + } + } + } + + private fun findViewTreeLifecycleOwnerFromAncestors(): LifecycleOwner? { + var parent = this.parent as? View ?: return null + while (true) { + parent.findViewTreeLifecycleOwner()?.let { + return it + } + parent = parent.parent as? View ?: return null + } + } + + fun blur() { + blurSignal.value = blurSignal.value + 1 + val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager + imm.hideSoftInputFromWindow(windowToken, 0) + clearFocus() + } + + fun focus() { + focusSignal.value = focusSignal.value + 1 + } + + private fun configureComponent(context: Context) { + setBackgroundColor(android.graphics.Color.TRANSPARENT) + clipChildren = false + clipToPadding = false + + layoutParams = LayoutParams( + LayoutParams.MATCH_PARENT, + LayoutParams.MATCH_PARENT + ) + + viewModel = JetpackComposeViewModel() + + addView(kbcLayoutHost) + + composeView = ComposeView(context).also { cv -> + cv.layoutParams = LayoutParams( + LayoutParams.MATCH_PARENT, + LayoutParams.MATCH_PARENT + ) + cv.setBackgroundColor(android.graphics.Color.TRANSPARENT) + cv.setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed) + cv.setContent { + val value = viewModel.value.collectAsState().value + val blurTick by blurSignal.collectAsState() + val focusTick by focusSignal.collectAsState() + val focusManager = LocalFocusManager.current + val focusRequester = remember { FocusRequester() } + + LaunchedEffect(blurTick) { + if (blurTick > 0) { + focusManager.clearFocus(force = true) + } + } + + LaunchedEffect(focusTick) { + if (focusTick > 0) { + focusRequester.requestFocus() + } + } + + JetpackComposeView( + value = value, + inputStyle = viewModel.inputStyle, + autoComplete = viewModel.autoComplete, + placeholder = viewModel.placeholder, + placeholderTextColor = viewModel.placeholderTextColor, + selectionColor = viewModel.selectionColor, + autoCapitalize = viewModel.autoCapitalize, + autoCorrect = viewModel.autoCorrect, + keyboardType = viewModel.keyboardType, + returnKeyType = viewModel.returnKeyType, + onTextChange = { value -> + val surfaceId = UIManagerHelper.getSurfaceId(context) + val viewId = this@ControlledInputView.id + UIManagerHelper + .getEventDispatcherForReactTag(context as ReactContext, viewId) + ?.dispatchEvent( + TextChangeEvent( + surfaceId, + viewId, + value + ) + ) + }, + onFocus = { + val surfaceId = UIManagerHelper.getSurfaceId(context) + val viewId = this@ControlledInputView.id + UIManagerHelper + .getEventDispatcherForReactTag(context as ReactContext, viewId) + ?.dispatchEvent(FocusEvent(surfaceId, viewId)) + post { syncKeyboardControllerFocusedInput() } + }, + onBlur = { + val surfaceId = UIManagerHelper.getSurfaceId(context) + val viewId = this@ControlledInputView.id + UIManagerHelper + .getEventDispatcherForReactTag(context as ReactContext, viewId) + ?.dispatchEvent(BlurEvent(surfaceId, viewId)) + }, + onSubmitEditing = { + val surfaceId = UIManagerHelper.getSurfaceId(context) + val viewId = this@ControlledInputView.id + UIManagerHelper + .getEventDispatcherForReactTag(context as ReactContext, viewId) + ?.dispatchEvent(SubmitEditingEvent(surfaceId, viewId)) + }, + focusRequester = focusRequester + ) + } + addView(cv) + } + } +} diff --git a/android/src/main/java/com/controlledinput/ControlledInputViewManager.kt b/android/src/main/java/com/controlledinput/ControlledInputViewManager.kt new file mode 100644 index 0000000..d3824ab --- /dev/null +++ b/android/src/main/java/com/controlledinput/ControlledInputViewManager.kt @@ -0,0 +1,120 @@ +package com.controlledinput + +import com.facebook.react.bridge.ReadableMap +import com.facebook.react.module.annotations.ReactModule +import com.facebook.react.uimanager.SimpleViewManager +import com.facebook.react.uimanager.ThemedReactContext +import com.facebook.react.uimanager.ViewManagerDelegate +import com.facebook.react.uimanager.annotations.ReactProp +import com.facebook.react.viewmanagers.ControlledInputViewManagerInterface +import com.facebook.react.viewmanagers.ControlledInputViewManagerDelegate +import com.facebook.react.common.MapBuilder + +@ReactModule(name = ControlledInputViewManager.NAME) +class ControlledInputViewManager : SimpleViewManager(), + ControlledInputViewManagerInterface { + private val mDelegate: ViewManagerDelegate + + init { + mDelegate = ControlledInputViewManagerDelegate(this) + } + + override fun getDelegate(): ViewManagerDelegate? { + return mDelegate + } + + override fun getName(): String { + return NAME + } + + public override fun createViewInstance(context: ThemedReactContext): ControlledInputView { + return ControlledInputView(context) + } + + @ReactProp(name = "value") + override fun setValue(view: ControlledInputView, value: String?) { + view.viewModel.setValue(value ?: "") + } + + @ReactProp(name = "placeholder") + override fun setPlaceholder(view: ControlledInputView, placeholder: String?) { + view.viewModel.setPlaceholder(placeholder) + } + + @ReactProp(name = "placeholderTextColor", customType = "Color") + override fun setPlaceholderTextColor(view: ControlledInputView, placeholderTextColor: Int?) { + view.viewModel.setPlaceholderTextColor(placeholderTextColor) + } + + @ReactProp(name = "selectionColor", customType = "Color") + override fun setSelectionColor(view: ControlledInputView, selectionColor: Int?) { + view.viewModel.setSelectionColor(selectionColor) + } + + @ReactProp(name = "autoComplete") + override fun setAutoComplete(view: ControlledInputView, autoComplete: String?) { + view.viewModel.setAutoCompleteWithAutofill(view, autoComplete) + } + + @ReactProp(name = "autoCapitalize") + override fun setAutoCapitalize(view: ControlledInputView, autoCapitalize: String?) { + view.viewModel.setAutoCapitalize(autoCapitalize) + } + + @ReactProp(name = "autoCorrect", defaultBoolean = true) + override fun setAutoCorrect(view: ControlledInputView, autoCorrect: Boolean) { + view.viewModel.setAutoCorrect(autoCorrect) + } + + @ReactProp(name = "keyboardType") + override fun setKeyboardType(view: ControlledInputView, keyboardType: String?) { + view.viewModel.setKeyboardType(keyboardType) + } + + @ReactProp(name = "returnKeyType") + override fun setReturnKeyType(view: ControlledInputView, returnKeyType: String?) { + view.viewModel.setReturnKeyType(returnKeyType) + } + + @ReactProp(name = "inputStyle") + override fun setInputStyle(view: ControlledInputView, inputStyle: ReadableMap?) { + val style = if (inputStyle == null) { + null + } else { + InputStyle( + color = if (inputStyle.hasKey("color")) inputStyle.getString("color") else null, + fontSize = if (inputStyle.hasKey("fontSize")) inputStyle.getDouble("fontSize") else null, + height = if (inputStyle.hasKey("height")) inputStyle.getDouble("height") else null, + fontFamily = if (inputStyle.hasKey("fontFamily")) inputStyle.getString("fontFamily") else null, + paddingTop = if (inputStyle.hasKey("paddingTop")) inputStyle.getDouble("paddingTop") else null, + paddingBottom = if (inputStyle.hasKey("paddingBottom")) inputStyle.getDouble("paddingBottom") else null, + paddingLeft = if (inputStyle.hasKey("paddingLeft")) inputStyle.getDouble("paddingLeft") else null, + paddingRight = if (inputStyle.hasKey("paddingRight")) inputStyle.getDouble("paddingRight") else null, + borderWidth = if (inputStyle.hasKey("borderWidth")) inputStyle.getDouble("borderWidth") else null, + borderRadius = if (inputStyle.hasKey("borderRadius")) inputStyle.getDouble("borderRadius") else null, + borderColor = if (inputStyle.hasKey("borderColor")) inputStyle.getString("borderColor") else null, + backgroundColor = if (inputStyle.hasKey("backgroundColor")) inputStyle.getString("backgroundColor") else null, + ) + } + view.viewModel.setInputStyle(style) + } + + companion object { + const val NAME = "ControlledInputView" + } + + override fun getExportedCustomDirectEventTypeConstants(): MutableMap = mutableMapOf( + TextChangeEvent.EVENT_NAME to MapBuilder.of("registrationName", "onChangeText"), + FocusEvent.EVENT_NAME to MapBuilder.of("registrationName", "onFocus"), + BlurEvent.EVENT_NAME to MapBuilder.of("registrationName", "onBlur"), + SubmitEditingEvent.EVENT_NAME to MapBuilder.of("registrationName", "onSubmitEditing") + ) + + override fun focus(view: ControlledInputView?) { + view?.focus() + } + + override fun blur(view: ControlledInputView?) { + view?.blur() + } +} diff --git a/android/src/main/java/com/controlledinput/JetpackComposeView.kt b/android/src/main/java/com/controlledinput/JetpackComposeView.kt new file mode 100644 index 0000000..f5f9f86 --- /dev/null +++ b/android/src/main/java/com/controlledinput/JetpackComposeView.kt @@ -0,0 +1,341 @@ +package com.controlledinput + +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.ui.Alignment +import androidx.compose.ui.draw.clip +import androidx.compose.foundation.text.BasicTextField +import androidx.compose.ui.unit.dp +import androidx.compose.foundation.text.input.InputTransformation +import androidx.compose.foundation.text.input.KeyboardActionHandler +import androidx.compose.foundation.text.input.TextFieldState +import androidx.compose.foundation.text.input.byValue +import androidx.compose.foundation.text.input.setTextAndPlaceCursorAtEnd +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.interaction.FocusInteraction +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.focus.FocusRequester +import androidx.compose.ui.focus.focusRequester +import android.graphics.Typeface +import androidx.compose.foundation.text.selection.LocalTextSelectionColors +import androidx.compose.foundation.text.selection.TextSelectionColors +import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.input.ImeAction +import androidx.compose.ui.text.input.KeyboardCapitalization +import androidx.compose.ui.text.input.KeyboardType +import androidx.compose.ui.autofill.AutofillNode +import androidx.compose.ui.autofill.AutofillType +import androidx.compose.ui.layout.onGloballyPositioned +import androidx.compose.ui.layout.boundsInWindow +import androidx.compose.ui.platform.LocalAutofill +import androidx.compose.ui.platform.LocalAutofillTree +import androidx.compose.ui.unit.sp +import com.facebook.react.bridge.Arguments +import com.facebook.react.bridge.WritableMap +import com.facebook.react.uimanager.events.Event +import kotlinx.coroutines.flow.StateFlow + +data class InputStyle( + val color: String? = null, + val fontSize: Double? = null, + val height: Double? = null, + val fontFamily: String? = null, + val paddingTop: Double? = null, + val paddingBottom: Double? = null, + val paddingLeft: Double? = null, + val paddingRight: Double? = null, + val borderWidth: Double? = null, + val borderRadius: Double? = null, + val borderColor: String? = null, + val backgroundColor: String? = null, +) + +@Composable +fun JetpackComposeView( + value: String, + inputStyle: StateFlow, + autoComplete: StateFlow, + placeholder: StateFlow, + placeholderTextColor: StateFlow, + selectionColor: StateFlow, + autoCapitalize: StateFlow, + autoCorrect: StateFlow, + keyboardType: StateFlow, + returnKeyType: StateFlow, + onTextChange: (value: String) -> Unit, + onFocus: (() -> Unit)? = null, + onBlur: (() -> Unit)? = null, + onSubmitEditing: (() -> Unit)? = null, + focusRequester: FocusRequester, +) { + val state = remember { TextFieldState(value) } + val style by inputStyle.collectAsState() + val keyboardTypeValue by keyboardType.collectAsState() + val autoCapitalizeValue by autoCapitalize.collectAsState() + val autoCorrectValue by autoCorrect.collectAsState() + val returnKeyTypeValue by returnKeyType.collectAsState() + val autoCompleteValue by autoComplete.collectAsState() + val placeholderValue by placeholder.collectAsState() + val placeholderTextColorValue by placeholderTextColor.collectAsState() + val selectionColorValue by selectionColor.collectAsState() + val interactionSource = remember { MutableInteractionSource() } + + val autofill = LocalAutofill.current + val autofillNode = remember { + AutofillNode( + autofillTypes = toAutofillTypes(autoCompleteValue), + onFill = { onTextChange(it) } + ) + } + LocalAutofillTree.current += autofillNode + + if (state.text.toString() != value) { + state.setTextAndPlaceCursorAtEnd(value) + } + + LaunchedEffect(interactionSource) { + interactionSource.interactions.collect { interaction -> + when (interaction) { + is FocusInteraction.Focus -> { + onFocus?.invoke() + autofill?.requestAutofillForNode(autofillNode) + } + is FocusInteraction.Unfocus -> { + onBlur?.invoke() + autofill?.cancelAutofillForNode(autofillNode) + } + } + } + } + + val context = LocalContext.current + val textColor = style?.color?.let { Color(android.graphics.Color.parseColor(it)) } ?: Color.White + val fontSize = style?.fontSize?.let { it.sp } ?: 24.sp + val fontFamily = remember(style?.fontFamily) { + style?.fontFamily?.let { name -> + try { + val typeface = com.facebook.react.views.text.ReactFontManager.getInstance() + .getTypeface(name, Typeface.NORMAL, context.assets) + typeface?.let { FontFamily(it) } + } catch (_: Exception) { + null + } + } + } + + val paddingTop = style?.paddingTop?.dp ?: 0.dp + val paddingBottom = style?.paddingBottom?.dp ?: 0.dp + val paddingLeft = style?.paddingLeft?.dp ?: 0.dp + val paddingRight = style?.paddingRight?.dp ?: 0.dp + val borderWidth = style?.borderWidth?.dp ?: 0.dp + val borderRadius = style?.borderRadius?.dp ?: 0.dp + val borderColor = style?.borderColor + ?.let { Color(android.graphics.Color.parseColor(it)) } + ?: Color.Transparent + val backgroundColor = style?.backgroundColor + ?.let { Color(android.graphics.Color.parseColor(it)) } + ?: Color.Transparent + val shape = RoundedCornerShape(borderRadius) + + val cursorColor = selectionColorValue?.let { Color(it) } ?: textColor + val textSelectionColors = remember(cursorColor) { + TextSelectionColors( + handleColor = cursorColor, + backgroundColor = cursorColor.copy(alpha = 0.4f) + ) + } + + CompositionLocalProvider(LocalTextSelectionColors provides textSelectionColors) { + Box( + modifier = Modifier + .fillMaxSize() + .clip(shape) + .background(backgroundColor) + .border(borderWidth, borderColor, shape), + ) { + BasicTextField( + state, + inputTransformation = InputTransformation.byValue { _, proposed -> + onTextChange(proposed.toString()) + proposed + }, + modifier = Modifier + .fillMaxSize() + .padding( + start = paddingLeft, + top = paddingTop, + end = paddingRight, + bottom = paddingBottom, + ) + .onGloballyPositioned { + autofillNode.boundingBox = it.boundsInWindow() + } + .focusRequester(focusRequester), + textStyle = TextStyle( + color = textColor, + fontSize = fontSize, + fontFamily = fontFamily, + ), + keyboardOptions = KeyboardOptions( + capitalization = toComposeCapitalization(autoCapitalizeValue), + keyboardType = toComposeKeyboardType(keyboardTypeValue), + imeAction = toComposeImeAction(returnKeyTypeValue), + autoCorrectEnabled = autoCorrectValue, + ), + onKeyboardAction = onSubmitEditing?.let { cb -> + KeyboardActionHandler { performDefaultAction -> + cb() + performDefaultAction() + } + }, + interactionSource = interactionSource, + cursorBrush = androidx.compose.ui.graphics.SolidColor(cursorColor), + decorator = { innerTextField -> + Box( + modifier = Modifier.fillMaxSize(), + contentAlignment = Alignment.CenterStart, + ) { + if (state.text.isEmpty() && !placeholderValue.isNullOrEmpty()) { + val finalPlaceholderColor = placeholderTextColorValue?.let { Color(it) } + ?: textColor.copy(alpha = 0.5f) + androidx.compose.material3.Text( + text = placeholderValue!!, + style = TextStyle( + color = finalPlaceholderColor, + fontSize = fontSize, + fontFamily = fontFamily, + ) + ) + } + innerTextField() + } + }, + ) + } + } +} + +private fun toComposeKeyboardType(value: String?): KeyboardType = when (value) { + "ascii-capable" -> KeyboardType.Ascii + "numbers-and-punctuation" -> KeyboardType.Text + "url" -> KeyboardType.Uri + "number-pad", "numeric" -> KeyboardType.Number + "phone-pad" -> KeyboardType.Phone + "email-address" -> KeyboardType.Email + "decimal-pad" -> KeyboardType.Decimal + "visible-password" -> KeyboardType.Password + else -> KeyboardType.Text +} + +private fun toComposeCapitalization(value: String?): KeyboardCapitalization = when (value) { + "none" -> KeyboardCapitalization.None + "characters" -> KeyboardCapitalization.Characters + "words" -> KeyboardCapitalization.Words + "sentences" -> KeyboardCapitalization.Sentences + else -> KeyboardCapitalization.Sentences +} + +private fun toComposeImeAction(value: String?): ImeAction = when (value) { + "go" -> ImeAction.Go + "next" -> ImeAction.Next + "search" -> ImeAction.Search + "send" -> ImeAction.Send + "done" -> ImeAction.Done + "none" -> ImeAction.None + "previous" -> ImeAction.Previous + else -> ImeAction.Default +} + +private fun toAutofillTypes(autoComplete: String?): List = when (autoComplete) { + "email" -> listOf(AutofillType.EmailAddress) + "name", "given-name", "family-name", "additional-name" -> listOf(AutofillType.PersonFullName) + "username" -> listOf(AutofillType.Username) + "password", "new-password" -> listOf(AutofillType.Password) + "tel" -> listOf(AutofillType.PhoneNumber) + "postal-code" -> listOf(AutofillType.PostalCode) + "street-address" -> listOf(AutofillType.AddressStreet) + "cc-number" -> listOf(AutofillType.CreditCardNumber) + "cc-exp" -> listOf(AutofillType.CreditCardExpirationDate) + "cc-exp-month" -> listOf(AutofillType.CreditCardExpirationMonth) + "cc-exp-year" -> listOf(AutofillType.CreditCardExpirationYear) + "cc-csc" -> listOf(AutofillType.CreditCardSecurityCode) + else -> emptyList() +} + +class TextChangeEvent( + surfaceId: Int, + viewId: Int, + val value: String, +) : Event(surfaceId, viewId) { + override fun getEventName() = EVENT_NAME + + override fun getCoalescingKey(): Short = 0 + + override fun getEventData(): WritableMap? = Arguments.createMap().also { + + it.putString("value", value) + } + + companion object { + const val EVENT_NAME = "onChangeText" + } +} + +class FocusEvent( + surfaceId: Int, + viewId: Int, +) : Event(surfaceId, viewId) { + override fun getEventName() = EVENT_NAME + + override fun getCoalescingKey(): Short = 0 + + override fun getEventData(): WritableMap? = Arguments.createMap() + + companion object { + const val EVENT_NAME = "onFocus" + } +} + +class BlurEvent( + surfaceId: Int, + viewId: Int, +) : Event(surfaceId, viewId) { + override fun getEventName() = EVENT_NAME + + override fun getCoalescingKey(): Short = 0 + + override fun getEventData(): WritableMap? = Arguments.createMap() + + companion object { + const val EVENT_NAME = "onBlur" + } +} + +class SubmitEditingEvent( + surfaceId: Int, + viewId: Int, +) : Event(surfaceId, viewId) { + override fun getEventName() = EVENT_NAME + + override fun getCoalescingKey(): Short = 0 + + override fun getEventData(): WritableMap? = Arguments.createMap() + + companion object { + const val EVENT_NAME = "onSubmitEditing" + } +} diff --git a/android/src/main/java/com/controlledinput/JetpackComposeViewModel.kt b/android/src/main/java/com/controlledinput/JetpackComposeViewModel.kt new file mode 100644 index 0000000..0a690a4 --- /dev/null +++ b/android/src/main/java/com/controlledinput/JetpackComposeViewModel.kt @@ -0,0 +1,104 @@ +package com.controlledinput + +import android.os.Build +import android.view.View +import androidx.lifecycle.ViewModel +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow + +class JetpackComposeViewModel : ViewModel() { + private val _value = MutableStateFlow("") + private val _inputStyle = MutableStateFlow(null) + private val _autoComplete = MutableStateFlow(null) + private val _placeholder = MutableStateFlow(null) + private val _placeholderTextColor = MutableStateFlow(null) + private val _selectionColor = MutableStateFlow(null) + private val _autoCapitalize = MutableStateFlow(null) + private val _autoCorrect = MutableStateFlow(true) + private val _keyboardType = MutableStateFlow(null) + private val _returnKeyType = MutableStateFlow(null) + + val value: StateFlow get() = _value + val inputStyle: StateFlow get() = _inputStyle + val autoComplete: StateFlow get() = _autoComplete + val placeholder: StateFlow get() = _placeholder + val placeholderTextColor: StateFlow get() = _placeholderTextColor + val selectionColor: StateFlow get() = _selectionColor + val autoCapitalize: StateFlow get() = _autoCapitalize + val autoCorrect: StateFlow get() = _autoCorrect + val keyboardType: StateFlow get() = _keyboardType + val returnKeyType: StateFlow get() = _returnKeyType + + fun setValue(newValue: String) { + _value.value = newValue + } + + fun setInputStyle(style: InputStyle?) { + _inputStyle.value = style + } + + fun setAutoComplete(newValue: String?) { + _autoComplete.value = newValue + } + + fun setPlaceholder(newValue: String?) { + _placeholder.value = newValue + } + + fun setPlaceholderTextColor(newValue: Int?) { + _placeholderTextColor.value = newValue + } + + fun setSelectionColor(newValue: Int?) { + _selectionColor.value = newValue + } + + fun setAutoCompleteWithAutofill(hostView: View, newValue: String?) { + setAutoComplete(newValue) + + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) { + return + } + + val hint = when (newValue) { + "email" -> View.AUTOFILL_HINT_EMAIL_ADDRESS + "name", "given-name", "family-name" -> View.AUTOFILL_HINT_NAME + "username" -> View.AUTOFILL_HINT_USERNAME + "password", "new-password" -> View.AUTOFILL_HINT_PASSWORD + "tel" -> View.AUTOFILL_HINT_PHONE + "postal-code" -> View.AUTOFILL_HINT_POSTAL_CODE + "street-address" -> View.AUTOFILL_HINT_POSTAL_ADDRESS + "cc-number" -> View.AUTOFILL_HINT_CREDIT_CARD_NUMBER + "cc-exp" -> View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE + "cc-exp-month" -> View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH + "cc-exp-year" -> View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR + "cc-csc" -> View.AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE + "additional-name" -> View.AUTOFILL_HINT_NAME + else -> null + } + + if (hint == null || newValue == "off" || newValue.isNullOrEmpty()) { + hostView.setAutofillHints(*emptyArray()) + return + } + + hostView.importantForAutofill = View.IMPORTANT_FOR_AUTOFILL_YES + hostView.setAutofillHints(hint) + } + + fun setAutoCapitalize(newValue: String?) { + _autoCapitalize.value = newValue + } + + fun setAutoCorrect(enabled: Boolean) { + _autoCorrect.value = enabled + } + + fun setKeyboardType(newValue: String?) { + _keyboardType.value = newValue + } + + fun setReturnKeyType(newValue: String?) { + _returnKeyType.value = newValue + } +} diff --git a/assets/date-controlled-input.gif b/assets/date-controlled-input.gif new file mode 100644 index 0000000..c2e1c2d Binary files /dev/null and b/assets/date-controlled-input.gif differ diff --git a/assets/date-default-input.gif b/assets/date-default-input.gif new file mode 100644 index 0000000..41cd11a Binary files /dev/null and b/assets/date-default-input.gif differ diff --git a/assets/promo-code-controlled-input.gif b/assets/promo-code-controlled-input.gif new file mode 100644 index 0000000..60d2c52 Binary files /dev/null and b/assets/promo-code-controlled-input.gif differ diff --git a/assets/promo-code-default-input.gif b/assets/promo-code-default-input.gif new file mode 100644 index 0000000..b6df103 Binary files /dev/null and b/assets/promo-code-default-input.gif differ diff --git a/babel.config.js b/babel.config.js new file mode 100644 index 0000000..0c05fd6 --- /dev/null +++ b/babel.config.js @@ -0,0 +1,12 @@ +module.exports = { + overrides: [ + { + exclude: /\/node_modules\//, + presets: ['module:react-native-builder-bob/babel-preset'], + }, + { + include: /\/node_modules\//, + presets: ['module:@react-native/babel-preset'], + }, + ], +}; diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 0000000..71f116a --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,258 @@ +import unusedImports from 'eslint-plugin-unused-imports'; +import _import from 'eslint-plugin-import'; +import { fixupPluginRules } from '@eslint/compat'; +import eslintConfigPrettier from 'eslint-config-prettier'; +import tseslint from 'typescript-eslint'; +import stylistic from '@stylistic/eslint-plugin'; +import globals from 'globals'; + +export default [ + { + ignores: [ + '**/node_modules', + '**/dist', + '**/lib', + 'eslint.config.mjs', + '**/build', + '**/coverage', + 'example/ios/Pods', + '**/.turbo', + ], + }, + eslintConfigPrettier, + { + files: ['**/*.ts', '**/*.tsx'], + plugins: { + '@typescript-eslint': tseslint.plugin, + 'unused-imports': unusedImports, + import: fixupPluginRules(_import), + '@stylistic': stylistic, + }, + + languageOptions: { + parser: tseslint.parser, + ecmaVersion: 6, + sourceType: 'commonjs', + + parserOptions: { + projectService: 'tsconfig.json', + + ecmaFeatures: { + jsx: true, + }, + }, + }, + + settings: { + 'import/parsers': { + '@typescript-eslint/parser': ['.ts', '.tsx'], + }, + + 'import/resolver': { + typescript: { + alwaysTryTypes: true, + }, + + node: { + extensions: ['.js', '.jsx', '.ts', '.tsx'], + }, + }, + }, + + rules: { + '@stylistic/quotes': [ + 'warn', + 'single', + { + allowTemplateLiterals: true, + }, + ], + + 'object-shorthand': 'warn', + '@stylistic/arrow-parens': ['warn', 'always'], + 'no-var': 'warn', + 'no-dupe-class-members': 'off', + 'import/prefer-default-export': 'off', + '@stylistic/implicit-arrow-linebreak': ['warn', 'beside'], + + '@stylistic/newline-per-chained-call': [ + 'warn', + { + ignoreChainWithDepth: 2, + }, + ], + + '@stylistic/function-call-argument-newline': ['warn', 'consistent'], + '@stylistic/function-paren-newline': ['warn', 'consistent'], + '@stylistic/array-element-newline': ['warn', 'consistent'], + + '@stylistic/array-bracket-newline': [ + 'warn', + { + multiline: true, + }, + ], + + '@stylistic/padding-line-between-statements': [ + 'warn', + { + blankLine: 'always', + prev: '*', + next: 'return', + }, + { + blankLine: 'always', + prev: '*', + next: 'multiline-block-like', + }, + ], + + '@typescript-eslint/no-use-before-define': [ + 'warn', + { + variables: false, + }, + ], + + '@stylistic/lines-between-class-members': ['warn'], + + '@typescript-eslint/no-inferrable-types': [ + 'warn', + { + ignoreParameters: true, + }, + ], + + '@typescript-eslint/explicit-module-boundary-types': [ + 'warn', + { + allowArgumentsExplicitlyTypedAsAny: true, + }, + ], + + '@typescript-eslint/no-explicit-any': 'off', + + '@typescript-eslint/explicit-member-accessibility': [ + 'warn', + { + accessibility: 'explicit', + + overrides: { + constructors: 'no-public', + }, + }, + ], + + '@typescript-eslint/explicit-function-return-type': [ + 'warn', + { + allowExpressions: true, + }, + ], + + '@typescript-eslint/no-require-imports': 'off', + '@typescript-eslint/no-unused-vars': 'off', + + '@typescript-eslint/array-type': [ + 'warn', + { + default: 'generic', + readonly: 'generic', + }, + ], + + '@typescript-eslint/member-ordering': [ + 'warn', + { + default: [ + 'public-static-field', + 'protected-static-field', + 'private-static-field', + 'public-instance-field', + 'protected-instance-field', + 'private-instance-field', + 'public-constructor', + 'protected-constructor', + 'private-constructor', + 'public-static-method', + 'public-instance-method', + 'protected-static-method', + 'protected-instance-method', + 'private-static-method', + 'private-instance-method', + ], + }, + ], + + '@typescript-eslint/naming-convention': [ + 'warn', + { + selector: 'typeLike', + format: ['PascalCase'], + }, + { + selector: ['parameter'], + format: ['camelCase', 'PascalCase'], + leadingUnderscore: 'allow', + }, + { + selector: ['classProperty'], + format: ['camelCase', 'snake_case'], + leadingUnderscore: 'allow', + }, + { + selector: ['method', 'accessor'], + format: ['camelCase'], + }, + { + selector: ['function', 'typeProperty'], + format: ['camelCase', 'PascalCase'], + }, + { + selector: 'variable', + format: ['camelCase', 'PascalCase', 'UPPER_CASE'], + }, + { + selector: 'enumMember', + format: ['UPPER_CASE'], + }, + ], + + 'unused-imports/no-unused-imports': 'error', + + 'unused-imports/no-unused-vars': [ + 'error', + { + vars: 'all', + varsIgnorePattern: '^_', + argsIgnorePattern: '^_', + ignoreRestSiblings: true, + caughtErrors: 'none', + }, + ], + + '@stylistic/jsx-quotes': ['warn', 'prefer-single'], + 'import/newline-after-import': 'warn', + 'import/no-unresolved': 'error', + + 'import/order': [ + 'warn', + { + groups: ['builtin', 'external', 'internal', 'parent', 'sibling', 'index', 'object', 'type'], + + alphabetize: { + order: 'asc', + }, + }, + ], + + 'import/no-duplicates': 'warn', + }, + }, + { + files: ['**/__tests__/**/*.{ts,tsx}', '**/*.test.{ts,tsx}'], + languageOptions: { + globals: globals.jest, + }, + }, +]; diff --git a/example/.bundle/config b/example/.bundle/config new file mode 100644 index 0000000..848943b --- /dev/null +++ b/example/.bundle/config @@ -0,0 +1,2 @@ +BUNDLE_PATH: "vendor/bundle" +BUNDLE_FORCE_RUBY_PLATFORM: 1 diff --git a/example/.watchmanconfig b/example/.watchmanconfig new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/example/.watchmanconfig @@ -0,0 +1 @@ +{} diff --git a/example/Gemfile b/example/Gemfile new file mode 100644 index 0000000..6a4c5f1 --- /dev/null +++ b/example/Gemfile @@ -0,0 +1,16 @@ +source 'https://rubygems.org' + +# You may use http://rbenv.org/ or https://rvm.io/ to install and use this version +ruby ">= 2.6.10" + +# Exclude problematic versions of cocoapods and activesupport that causes build failures. +gem 'cocoapods', '>= 1.13', '!= 1.15.0', '!= 1.15.1' +gem 'activesupport', '>= 6.1.7.5', '!= 7.1.0' +gem 'xcodeproj', '< 1.26.0' +gem 'concurrent-ruby', '< 1.3.4' + +# Ruby 3.4.0 has removed some libraries from the standard library. +gem 'bigdecimal' +gem 'logger' +gem 'benchmark' +gem 'mutex_m' diff --git a/example/Gemfile.lock b/example/Gemfile.lock new file mode 100644 index 0000000..ff53663 --- /dev/null +++ b/example/Gemfile.lock @@ -0,0 +1,112 @@ +GEM + remote: https://rubygems.org/ + specs: + CFPropertyList (3.0.9) + activesupport (6.1.7.10) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + zeitwerk (~> 2.3) + addressable (2.8.9) + public_suffix (>= 2.0.2, < 8.0) + algoliasearch (1.27.5) + httpclient (~> 2.8, >= 2.8.3) + json (>= 1.5.1) + atomos (0.1.3) + benchmark (0.5.0) + bigdecimal (4.0.1) + claide (1.1.0) + cocoapods (1.15.2) + addressable (~> 2.8) + claide (>= 1.0.2, < 2.0) + cocoapods-core (= 1.15.2) + cocoapods-deintegrate (>= 1.0.3, < 2.0) + cocoapods-downloader (>= 2.1, < 3.0) + cocoapods-plugins (>= 1.0.0, < 2.0) + cocoapods-search (>= 1.0.0, < 2.0) + cocoapods-trunk (>= 1.6.0, < 2.0) + cocoapods-try (>= 1.1.0, < 2.0) + colored2 (~> 3.1) + escape (~> 0.0.4) + fourflusher (>= 2.3.0, < 3.0) + gh_inspector (~> 1.0) + molinillo (~> 0.8.0) + nap (~> 1.0) + ruby-macho (>= 2.3.0, < 3.0) + xcodeproj (>= 1.23.0, < 2.0) + cocoapods-core (1.15.2) + activesupport (>= 5.0, < 8) + addressable (~> 2.8) + algoliasearch (~> 1.0) + concurrent-ruby (~> 1.1) + fuzzy_match (~> 2.0.4) + nap (~> 1.0) + netrc (~> 0.11) + public_suffix (~> 4.0) + typhoeus (~> 1.0) + cocoapods-deintegrate (1.0.5) + cocoapods-downloader (2.1) + cocoapods-plugins (1.0.0) + nap + cocoapods-search (1.0.1) + cocoapods-trunk (1.6.0) + nap (>= 0.8, < 2.0) + netrc (~> 0.11) + cocoapods-try (1.2.0) + colored2 (3.1.2) + concurrent-ruby (1.3.3) + escape (0.0.4) + ethon (0.18.0) + ffi (>= 1.15.0) + logger + ffi (1.17.3) + fourflusher (2.3.1) + fuzzy_match (2.0.4) + gh_inspector (1.1.3) + httpclient (2.9.0) + mutex_m + i18n (1.14.8) + concurrent-ruby (~> 1.0) + json (2.7.6) + logger (1.7.0) + minitest (5.25.4) + molinillo (0.8.0) + mutex_m (0.3.0) + nanaimo (0.3.0) + nap (1.1.0) + netrc (0.11.0) + public_suffix (4.0.7) + rexml (3.4.4) + ruby-macho (2.5.1) + typhoeus (1.6.0) + ethon (>= 0.18.0) + tzinfo (2.0.6) + concurrent-ruby (~> 1.0) + xcodeproj (1.25.1) + CFPropertyList (>= 2.3.3, < 4.0) + atomos (~> 0.1.3) + claide (>= 1.0.2, < 2.0) + colored2 (~> 3.1) + nanaimo (~> 0.3.0) + rexml (>= 3.3.6, < 4.0) + zeitwerk (2.6.18) + +PLATFORMS + ruby + +DEPENDENCIES + activesupport (>= 6.1.7.5, != 7.1.0) + benchmark + bigdecimal + cocoapods (>= 1.13, != 1.15.1, != 1.15.0) + concurrent-ruby (< 1.3.4) + logger + mutex_m + xcodeproj (< 1.26.0) + +RUBY VERSION + ruby 2.6.10p210 + +BUNDLED WITH + 1.17.2 diff --git a/example/README.md b/example/README.md new file mode 100644 index 0000000..a88d359 --- /dev/null +++ b/example/README.md @@ -0,0 +1,91 @@ +This is a new [**React Native**](https://reactnative.dev) project, bootstrapped using [`@react-native-community/cli`](https://github.com/react-native-community/cli). + +# Getting Started + +> **Note**: Make sure you have completed the [Set Up Your Environment](https://reactnative.dev/docs/set-up-your-environment) guide before proceeding. + +## Step 1: Start Metro + +First, you will need to run **Metro**, the JavaScript build tool for React Native. + +To start the Metro dev server, run the following command from the root of your React Native project: + +```sh +npm start +``` + +From the repository root (npm workspaces): + +```sh +npm run start -w react-native-controlled-input-example +``` + +## Step 2: Build and run your app + +With Metro running, open a new terminal window/pane from the root of your React Native project, and use one of the following commands to build and run your Android or iOS app: + +### Android + +```sh +npm run android +``` + +### iOS + +For iOS, remember to install CocoaPods dependencies (this only needs to be run on first clone or after updating native deps). + +The first time you create a new project, run the Ruby bundler to install CocoaPods itself: + +```sh +bundle install +``` + +Then, and every time you update your native dependencies, run: + +```sh +bundle exec pod install +``` + +For more information, please visit [CocoaPods Getting Started guide](https://guides.cocoapods.org/using/getting-started.html). + +```sh +npm run ios +``` + +If everything is set up correctly, you should see your new app running in the Android Emulator, iOS Simulator, or your connected device. + +This is one way to run your app — you can also build it directly from Android Studio or Xcode. + +## Step 3: Modify your app + +Now that you have successfully run the app, let's make changes! + +Open `App.tsx` in your text editor of choice and make some changes. When you save, your app will automatically update and reflect these changes — this is powered by [Fast Refresh](https://reactnative.dev/docs/fast-refresh). + +When you want to forcefully reload, for example to reset the state of your app, you can perform a full reload: + +- **Android**: Press the R key twice or select **"Reload"** from the **Dev Menu**, accessed via Ctrl + M (Windows/Linux) or Cmd ⌘ + M (macOS). +- **iOS**: Press R in iOS Simulator. + +## Congratulations! :tada: + +You've successfully run and modified your React Native App. :partying_face: + +### Now what? + +- If you want to add this new React Native code to an existing application, check out the [Integration guide](https://reactnative.dev/docs/integration-with-existing-apps). +- If you're curious to learn more about React Native, check out the [docs](https://reactnative.dev/docs/getting-started). + +# Troubleshooting + +If you're having issues getting the above steps to work, see the [Troubleshooting](https://reactnative.dev/docs/troubleshooting) page. + +# Learn More + +To learn more about React Native, take a look at the following resources: + +- [React Native Website](https://reactnative.dev) - learn more about React Native. +- [Getting Started](https://reactnative.dev/docs/environment-setup) - an **overview** of React Native and how setup your environment. +- [Learn the Basics](https://reactnative.dev/docs/getting-started) - a **guided tour** of the React Native **basics**. +- [Blog](https://reactnative.dev/blog) - read the latest official React Native **Blog** posts. +- [`@facebook/react-native`](https://github.com/facebook/react-native) - the Open Source; GitHub **repository** for React Native. diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle new file mode 100644 index 0000000..1f06ecb --- /dev/null +++ b/example/android/app/build.gradle @@ -0,0 +1,119 @@ +apply plugin: "com.android.application" +apply plugin: "org.jetbrains.kotlin.android" +apply plugin: "com.facebook.react" + +/** + * This is the configuration block to customize your React Native Android app. + * By default you don't need to apply any configuration, just uncomment the lines you need. + */ +react { + /* Folders */ + // The root of your project, i.e. where "package.json" lives. Default is '../..' + // root = file("../../") + // The folder where the react-native NPM package is. Default is ../../node_modules/react-native + // reactNativeDir = file("../../node_modules/react-native") + // The folder where the react-native Codegen package is. Default is ../../node_modules/@react-native/codegen + // codegenDir = file("../../node_modules/@react-native/codegen") + // The cli.js file which is the React Native CLI entrypoint. Default is ../../node_modules/react-native/cli.js + // cliFile = file("../../node_modules/react-native/cli.js") + + /* Variants */ + // The list of variants to that are debuggable. For those we're going to + // skip the bundling of the JS bundle and the assets. By default is just 'debug'. + // If you add flavors like lite, prod, etc. you'll have to list your debuggableVariants. + // debuggableVariants = ["liteDebug", "prodDebug"] + + /* Bundling */ + // A list containing the node command and its flags. Default is just 'node'. + // nodeExecutableAndArgs = ["node"] + // + // The command to run when bundling. By default is 'bundle' + // bundleCommand = "ram-bundle" + // + // The path to the CLI configuration file. Default is empty. + // bundleConfig = file(../rn-cli.config.js) + // + // The name of the generated asset file containing your JS bundle + // bundleAssetName = "MyApplication.android.bundle" + // + // The entry file for bundle generation. Default is 'index.android.js' or 'index.js' + // entryFile = file("../js/MyApplication.android.js") + // + // A list of extra flags to pass to the 'bundle' commands. + // See https://github.com/react-native-community/cli/blob/main/docs/commands.md#bundle + // extraPackagerArgs = [] + + /* Hermes Commands */ + // The hermes compiler command to run. By default it is 'hermesc' + // hermesCommand = "$rootDir/my-custom-hermesc/bin/hermesc" + // + // The list of flags to pass to the Hermes compiler. By default is "-O", "-output-source-map" + // hermesFlags = ["-O", "-output-source-map"] + + /* Autolinking */ + autolinkLibrariesWithApp() +} + +/** + * Set this to true to Run Proguard on Release builds to minify the Java bytecode. + */ +def enableProguardInReleaseBuilds = false + +/** + * The preferred build flavor of JavaScriptCore (JSC) + * + * For example, to use the international variant, you can use: + * `def jscFlavor = io.github.react-native-community:jsc-android-intl:2026004.+` + * + * The international variant includes ICU i18n library and necessary data + * allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that + * give correct results when using with locales other than en-US. Note that + * this variant is about 6MiB larger per architecture than default. + */ +def jscFlavor = 'io.github.react-native-community:jsc-android:2026004.+' + +android { + ndkVersion rootProject.ext.ndkVersion + buildToolsVersion rootProject.ext.buildToolsVersion + compileSdk rootProject.ext.compileSdkVersion + + namespace "controlledinput.example" + defaultConfig { + applicationId "controlledinput.example" + minSdkVersion rootProject.ext.minSdkVersion + targetSdkVersion rootProject.ext.targetSdkVersion + versionCode 1 + versionName "1.0" + } + signingConfigs { + debug { + storeFile file('debug.keystore') + storePassword 'android' + keyAlias 'androiddebugkey' + keyPassword 'android' + } + } + buildTypes { + debug { + signingConfig signingConfigs.debug + } + release { + // Caution! In production, you need to generate your own keystore file. + // see https://reactnative.dev/docs/signed-apk-android. + signingConfig signingConfigs.debug + minifyEnabled enableProguardInReleaseBuilds + proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" + } + } +} + +dependencies { + // The version of react-native is set by the React Native Gradle Plugin + implementation("com.facebook.react:react-android") + + if (hermesEnabled.toBoolean()) { + implementation("com.facebook.react:hermes-android") + } else { + implementation jscFlavor + } +} diff --git a/example/android/app/debug.keystore b/example/android/app/debug.keystore new file mode 100644 index 0000000..364e105 Binary files /dev/null and b/example/android/app/debug.keystore differ diff --git a/example/android/app/proguard-rules.pro b/example/android/app/proguard-rules.pro new file mode 100644 index 0000000..11b0257 --- /dev/null +++ b/example/android/app/proguard-rules.pro @@ -0,0 +1,10 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: diff --git a/example/android/app/src/main/AndroidManifest.xml b/example/android/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..fb78f39 --- /dev/null +++ b/example/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + diff --git a/example/android/app/src/main/assets/fonts/AlbertSans-Regular.otf b/example/android/app/src/main/assets/fonts/AlbertSans-Regular.otf new file mode 100644 index 0000000..aaa19f7 Binary files /dev/null and b/example/android/app/src/main/assets/fonts/AlbertSans-Regular.otf differ diff --git a/example/android/app/src/main/java/controlledinput/example/MainActivity.kt b/example/android/app/src/main/java/controlledinput/example/MainActivity.kt new file mode 100644 index 0000000..26cc95f --- /dev/null +++ b/example/android/app/src/main/java/controlledinput/example/MainActivity.kt @@ -0,0 +1,22 @@ +package controlledinput.example + +import com.facebook.react.ReactActivity +import com.facebook.react.ReactActivityDelegate +import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.fabricEnabled +import com.facebook.react.defaults.DefaultReactActivityDelegate + +class MainActivity : ReactActivity() { + + /** + * Returns the name of the main component registered from JavaScript. This is used to schedule + * rendering of the component. + */ + override fun getMainComponentName(): String = "ControlledInputExample" + + /** + * Returns the instance of the [ReactActivityDelegate]. We use [DefaultReactActivityDelegate] + * which allows you to enable New Architecture with a single boolean flags [fabricEnabled] + */ + override fun createReactActivityDelegate(): ReactActivityDelegate = + DefaultReactActivityDelegate(this, mainComponentName, fabricEnabled) +} diff --git a/example/android/app/src/main/java/controlledinput/example/MainApplication.kt b/example/android/app/src/main/java/controlledinput/example/MainApplication.kt new file mode 100644 index 0000000..87a91f8 --- /dev/null +++ b/example/android/app/src/main/java/controlledinput/example/MainApplication.kt @@ -0,0 +1,27 @@ +package controlledinput.example + +import android.app.Application +import com.facebook.react.PackageList +import com.facebook.react.ReactApplication +import com.facebook.react.ReactHost +import com.facebook.react.ReactNativeApplicationEntryPoint.loadReactNative +import com.facebook.react.defaults.DefaultReactHost.getDefaultReactHost + +class MainApplication : Application(), ReactApplication { + + override val reactHost: ReactHost by lazy { + getDefaultReactHost( + context = applicationContext, + packageList = + PackageList(this).packages.apply { + // Packages that cannot be autolinked yet can be added manually here, for example: + // add(MyReactNativePackage()) + }, + ) + } + + override fun onCreate() { + super.onCreate() + loadReactNative(this) + } +} diff --git a/example/android/app/src/main/res/drawable/rn_edit_text_material.xml b/example/android/app/src/main/res/drawable/rn_edit_text_material.xml new file mode 100644 index 0000000..5c25e72 --- /dev/null +++ b/example/android/app/src/main/res/drawable/rn_edit_text_material.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + diff --git a/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000..a2f5908 Binary files /dev/null and b/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/example/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/example/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png new file mode 100644 index 0000000..1b52399 Binary files /dev/null and b/example/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ diff --git a/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000..ff10afd Binary files /dev/null and b/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/example/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/example/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png new file mode 100644 index 0000000..115a4c7 Binary files /dev/null and b/example/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ diff --git a/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000..dcd3cd8 Binary files /dev/null and b/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png new file mode 100644 index 0000000..459ca60 Binary files /dev/null and b/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ diff --git a/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000..8ca12fe Binary files /dev/null and b/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png new file mode 100644 index 0000000..8e19b41 Binary files /dev/null and b/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ diff --git a/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000..b824ebd Binary files /dev/null and b/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png new file mode 100644 index 0000000..4c19a13 Binary files /dev/null and b/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ diff --git a/example/android/app/src/main/res/values/strings.xml b/example/android/app/src/main/res/values/strings.xml new file mode 100644 index 0000000..636eb53 --- /dev/null +++ b/example/android/app/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + ControlledInputExample + diff --git a/example/android/app/src/main/res/values/styles.xml b/example/android/app/src/main/res/values/styles.xml new file mode 100644 index 0000000..7ba83a2 --- /dev/null +++ b/example/android/app/src/main/res/values/styles.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/example/android/build.gradle b/example/android/build.gradle new file mode 100644 index 0000000..dad99b0 --- /dev/null +++ b/example/android/build.gradle @@ -0,0 +1,21 @@ +buildscript { + ext { + buildToolsVersion = "36.0.0" + minSdkVersion = 24 + compileSdkVersion = 36 + targetSdkVersion = 36 + ndkVersion = "27.1.12297006" + kotlinVersion = "2.1.20" + } + repositories { + google() + mavenCentral() + } + dependencies { + classpath("com.android.tools.build:gradle") + classpath("com.facebook.react:react-native-gradle-plugin") + classpath("org.jetbrains.kotlin:kotlin-gradle-plugin") + } +} + +apply plugin: "com.facebook.react.rootproject" diff --git a/example/android/gradle.properties b/example/android/gradle.properties new file mode 100644 index 0000000..9afe615 --- /dev/null +++ b/example/android/gradle.properties @@ -0,0 +1,44 @@ +# Project-wide Gradle settings. + +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. + +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html + +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +# Default value: -Xmx512m -XX:MaxMetaspaceSize=256m +org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m + +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true + +# AndroidX package structure to make it clearer which packages are bundled with the +# Android operating system, and which are packaged with your app's APK +# https://developer.android.com/topic/libraries/support-library/androidx-rn +android.useAndroidX=true + +# Use this property to specify which architecture you want to build. +# You can also override it from the CLI using +# ./gradlew -PreactNativeArchitectures=x86_64 +reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64 + +# Use this property to enable support to the new architecture. +# This will allow you to use TurboModules and the Fabric render in +# your application. You should enable this flag either if you want +# to write custom TurboModules/Fabric components OR use libraries that +# are providing them. +newArchEnabled=true + +# Use this property to enable or disable the Hermes JS engine. +# If set to false, you will be using JSC instead. +hermesEnabled=true + +# Use this property to enable edge-to-edge display support. +# This allows your app to draw behind system bars for an immersive UI. +# Note: Only works with ReactActivity and should not be used with custom Activity. +edgeToEdgeEnabled=false diff --git a/example/android/gradle/wrapper/gradle-wrapper.jar b/example/android/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..8bdaf60 Binary files /dev/null and b/example/android/gradle/wrapper/gradle-wrapper.jar differ diff --git a/example/android/gradle/wrapper/gradle-wrapper.properties b/example/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..2a84e18 --- /dev/null +++ b/example/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-9.0.0-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/example/android/gradlew b/example/android/gradlew new file mode 100755 index 0000000..ef07e01 --- /dev/null +++ b/example/android/gradlew @@ -0,0 +1,251 @@ +#!/bin/sh + +# +# Copyright © 2015 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH="\\\"\\\"" + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/example/android/gradlew.bat b/example/android/gradlew.bat new file mode 100644 index 0000000..dd2b8ee --- /dev/null +++ b/example/android/gradlew.bat @@ -0,0 +1,99 @@ +@REM Copyright (c) Meta Platforms, Inc. and affiliates. +@REM +@REM This source code is licensed under the MIT license found in the +@REM LICENSE file in the root directory of this source tree. + +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH= + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/example/android/link-assets-manifest.json b/example/android/link-assets-manifest.json new file mode 100644 index 0000000..05ce0a7 --- /dev/null +++ b/example/android/link-assets-manifest.json @@ -0,0 +1,9 @@ +{ + "migIndex": 1, + "data": [ + { + "path": "assets/fonts/AlbertSans-Regular.otf", + "sha1": "b8531ef6d9af4a5909ab4bdb1538476e5dc28284" + } + ] +} \ No newline at end of file diff --git a/example/android/settings.gradle b/example/android/settings.gradle new file mode 100644 index 0000000..f4bbaac --- /dev/null +++ b/example/android/settings.gradle @@ -0,0 +1,6 @@ +pluginManagement { includeBuild("../node_modules/@react-native/gradle-plugin") } +plugins { id("com.facebook.react.settings") } +extensions.configure(com.facebook.react.ReactSettingsExtension){ ex -> ex.autolinkLibrariesFromCommand() } +rootProject.name = 'controlledinput.example' +include ':app' +includeBuild('../node_modules/@react-native/gradle-plugin') diff --git a/example/app.json b/example/app.json new file mode 100644 index 0000000..a8c21e8 --- /dev/null +++ b/example/app.json @@ -0,0 +1,4 @@ +{ + "name": "ControlledInputExample", + "displayName": "ControlledInputExample" +} diff --git a/example/assets/fonts/AlbertSans-Regular.otf b/example/assets/fonts/AlbertSans-Regular.otf new file mode 100644 index 0000000..aaa19f7 Binary files /dev/null and b/example/assets/fonts/AlbertSans-Regular.otf differ diff --git a/example/babel.config.js b/example/babel.config.js new file mode 100644 index 0000000..486a093 --- /dev/null +++ b/example/babel.config.js @@ -0,0 +1,12 @@ +const path = require('path'); +const { getConfig } = require('react-native-builder-bob/babel-config'); +const pkg = require('../package.json'); + +const root = path.resolve(__dirname, '..'); + +module.exports = getConfig( + { + presets: ['module:@react-native/babel-preset'], + }, + { root, pkg } +); diff --git a/example/index.js b/example/index.js new file mode 100644 index 0000000..117ddca --- /dev/null +++ b/example/index.js @@ -0,0 +1,5 @@ +import { AppRegistry } from 'react-native'; +import App from './src/App'; +import { name as appName } from './app.json'; + +AppRegistry.registerComponent(appName, () => App); diff --git a/example/ios/.xcode.env b/example/ios/.xcode.env new file mode 100644 index 0000000..3d5782c --- /dev/null +++ b/example/ios/.xcode.env @@ -0,0 +1,11 @@ +# This `.xcode.env` file is versioned and is used to source the environment +# used when running script phases inside Xcode. +# To customize your local environment, you can create an `.xcode.env.local` +# file that is not versioned. + +# NODE_BINARY variable contains the PATH to the node executable. +# +# Customize the NODE_BINARY variable here. +# For example, to use nvm with brew, add the following line +# . "$(brew --prefix nvm)/nvm.sh" --no-use +export NODE_BINARY=$(command -v node) diff --git a/example/ios/ControlledInputExample.xcodeproj/project.pbxproj b/example/ios/ControlledInputExample.xcodeproj/project.pbxproj new file mode 100644 index 0000000..c31febb --- /dev/null +++ b/example/ios/ControlledInputExample.xcodeproj/project.pbxproj @@ -0,0 +1,493 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXBuildFile section */ + 09255987F7594F92B3148142 /* AlbertSans-Regular.otf in Resources */ = {isa = PBXBuildFile; fileRef = A4C9B72BE37842CD858B5146 /* AlbertSans-Regular.otf */; }; + 0C80B921A6F3F58F76C31292 /* libPods-ControlledInputExample.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5DCACB8F33CDC322A6C60F78 /* libPods-ControlledInputExample.a */; }; + 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; }; + 72990D94883B77AEEDFE4395 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB81A68108700A75B9A /* PrivacyInfo.xcprivacy */; }; + 761780ED2CA45674006654EE /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 761780EC2CA45674006654EE /* AppDelegate.swift */; }; + 81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 13B07F961A680F5B00A75B9A /* ControlledInputExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ControlledInputExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = ControlledInputExample/Images.xcassets; sourceTree = ""; }; + 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = ControlledInputExample/Info.plist; sourceTree = ""; }; + 13B07FB81A68108700A75B9A /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = PrivacyInfo.xcprivacy; path = ControlledInputExample/PrivacyInfo.xcprivacy; sourceTree = ""; }; + 3B4392A12AC88292D35C810B /* Pods-ControlledInputExample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ControlledInputExample.debug.xcconfig"; path = "Target Support Files/Pods-ControlledInputExample/Pods-ControlledInputExample.debug.xcconfig"; sourceTree = ""; }; + 5709B34CF0A7D63546082F79 /* Pods-ControlledInputExample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ControlledInputExample.release.xcconfig"; path = "Target Support Files/Pods-ControlledInputExample/Pods-ControlledInputExample.release.xcconfig"; sourceTree = ""; }; + 5DCACB8F33CDC322A6C60F78 /* libPods-ControlledInputExample.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-ControlledInputExample.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + 761780EC2CA45674006654EE /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = AppDelegate.swift; path = ControlledInputExample/AppDelegate.swift; sourceTree = ""; }; + 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = LaunchScreen.storyboard; path = ControlledInputExample/LaunchScreen.storyboard; sourceTree = ""; }; + A4C9B72BE37842CD858B5146 /* AlbertSans-Regular.otf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = undefined; includeInIndex = 0; lastKnownFileType = unknown; name = "AlbertSans-Regular.otf"; path = "../assets/fonts/AlbertSans-Regular.otf"; sourceTree = ""; }; + ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 13B07F8C1A680F5B00A75B9A /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 0C80B921A6F3F58F76C31292 /* libPods-ControlledInputExample.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 13B07FAE1A68108700A75B9A /* ControlledInputExample */ = { + isa = PBXGroup; + children = ( + 13B07FB51A68108700A75B9A /* Images.xcassets */, + 761780EC2CA45674006654EE /* AppDelegate.swift */, + 13B07FB61A68108700A75B9A /* Info.plist */, + 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */, + 13B07FB81A68108700A75B9A /* PrivacyInfo.xcprivacy */, + ); + name = ControlledInputExample; + sourceTree = ""; + }; + 2D16E6871FA4F8E400B85C8A /* Frameworks */ = { + isa = PBXGroup; + children = ( + ED297162215061F000B7C4FE /* JavaScriptCore.framework */, + 5DCACB8F33CDC322A6C60F78 /* libPods-ControlledInputExample.a */, + ); + name = Frameworks; + sourceTree = ""; + }; + 7191D5DAE071478BAB4EC3EB /* Resources */ = { + isa = PBXGroup; + children = ( + A4C9B72BE37842CD858B5146 /* AlbertSans-Regular.otf */, + ); + name = Resources; + path = ""; + sourceTree = ""; + }; + 832341AE1AAA6A7D00B99B32 /* Libraries */ = { + isa = PBXGroup; + children = ( + ); + name = Libraries; + sourceTree = ""; + }; + 83CBB9F61A601CBA00E9B192 = { + isa = PBXGroup; + children = ( + 13B07FAE1A68108700A75B9A /* ControlledInputExample */, + 832341AE1AAA6A7D00B99B32 /* Libraries */, + 83CBBA001A601CBA00E9B192 /* Products */, + 2D16E6871FA4F8E400B85C8A /* Frameworks */, + BBD78D7AC51CEA395F1C20DB /* Pods */, + 7191D5DAE071478BAB4EC3EB /* Resources */, + ); + indentWidth = 2; + sourceTree = ""; + tabWidth = 2; + usesTabs = 0; + }; + 83CBBA001A601CBA00E9B192 /* Products */ = { + isa = PBXGroup; + children = ( + 13B07F961A680F5B00A75B9A /* ControlledInputExample.app */, + ); + name = Products; + sourceTree = ""; + }; + BBD78D7AC51CEA395F1C20DB /* Pods */ = { + isa = PBXGroup; + children = ( + 3B4392A12AC88292D35C810B /* Pods-ControlledInputExample.debug.xcconfig */, + 5709B34CF0A7D63546082F79 /* Pods-ControlledInputExample.release.xcconfig */, + ); + path = Pods; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 13B07F861A680F5B00A75B9A /* ControlledInputExample */ = { + isa = PBXNativeTarget; + buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "ControlledInputExample" */; + buildPhases = ( + C38B50BA6285516D6DCD4F65 /* [CP] Check Pods Manifest.lock */, + 13B07F871A680F5B00A75B9A /* Sources */, + 13B07F8C1A680F5B00A75B9A /* Frameworks */, + 13B07F8E1A680F5B00A75B9A /* Resources */, + 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */, + 00EEFC60759A1932668264C0 /* [CP] Embed Pods Frameworks */, + E235C05ADACE081382539298 /* [CP] Copy Pods Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = ControlledInputExample; + productName = ControlledInputExample; + productReference = 13B07F961A680F5B00A75B9A /* ControlledInputExample.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 83CBB9F71A601CBA00E9B192 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 1210; + TargetAttributes = { + 13B07F861A680F5B00A75B9A = { + LastSwiftMigration = 1120; + }; + }; + }; + buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "ControlledInputExample" */; + compatibilityVersion = "Xcode 12.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 83CBB9F61A601CBA00E9B192; + productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 13B07F861A680F5B00A75B9A /* ControlledInputExample */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 13B07F8E1A680F5B00A75B9A /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */, + 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */, + 72990D94883B77AEEDFE4395 /* PrivacyInfo.xcprivacy in Resources */, + 09255987F7594F92B3148142 /* AlbertSans-Regular.otf in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "$(SRCROOT)/.xcode.env.local", + "$(SRCROOT)/.xcode.env", + ); + name = "Bundle React Native code and images"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "set -e\n\nWITH_ENVIRONMENT=\"$REACT_NATIVE_PATH/scripts/xcode/with-environment.sh\"\nREACT_NATIVE_XCODE=\"$REACT_NATIVE_PATH/scripts/react-native-xcode.sh\"\n\n/bin/sh -c \"\\\"$WITH_ENVIRONMENT\\\" \\\"$REACT_NATIVE_XCODE\\\"\"\n"; + }; + 00EEFC60759A1932668264C0 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-ControlledInputExample/Pods-ControlledInputExample-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-ControlledInputExample/Pods-ControlledInputExample-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-ControlledInputExample/Pods-ControlledInputExample-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + C38B50BA6285516D6DCD4F65 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-ControlledInputExample-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + E235C05ADACE081382539298 /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-ControlledInputExample/Pods-ControlledInputExample-resources-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Copy Pods Resources"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-ControlledInputExample/Pods-ControlledInputExample-resources-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-ControlledInputExample/Pods-ControlledInputExample-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 13B07F871A680F5B00A75B9A /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 761780ED2CA45674006654EE /* AppDelegate.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 13B07F941A680F5B00A75B9A /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 3B4392A12AC88292D35C810B /* Pods-ControlledInputExample.debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = 1; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = ControlledInputExample/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 15.1; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + OTHER_LDFLAGS = ( + "$(inherited)", + "-ObjC", + "-lc++", + ); + PRODUCT_BUNDLE_IDENTIFIER = controlledinput.example; + PRODUCT_NAME = ControlledInputExample; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Debug; + }; + 13B07F951A680F5B00A75B9A /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 5709B34CF0A7D63546082F79 /* Pods-ControlledInputExample.release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = 1; + INFOPLIST_FILE = ControlledInputExample/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 15.1; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + OTHER_LDFLAGS = ( + "$(inherited)", + "-ObjC", + "-lc++", + ); + PRODUCT_BUNDLE_IDENTIFIER = controlledinput.example; + PRODUCT_NAME = ControlledInputExample; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; + 83CBBA201A601CBA00E9B192 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_CXX_LANGUAGE_STANDARD = "c++20"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = ""; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 15.1; + LD_RUNPATH_SEARCH_PATHS = ( + /usr/lib/swift, + "$(inherited)", + ); + LIBRARY_SEARCH_PATHS = ( + "\"$(SDKROOT)/usr/lib/swift\"", + "\"$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)\"", + "\"$(inherited)\"", + ); + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + OTHER_CFLAGS = "$(inherited)"; + OTHER_CPLUSPLUSFLAGS = ( + "$(OTHER_CFLAGS)", + "-DFOLLY_NO_CONFIG", + "-DFOLLY_MOBILE=1", + "-DFOLLY_USE_LIBCPP=1", + "-DFOLLY_CFG_NO_COROUTINES=1", + "-DFOLLY_HAVE_CLOCK_GETTIME=1", + ); + REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) DEBUG"; + USE_HERMES = true; + }; + name = Debug; + }; + 83CBBA211A601CBA00E9B192 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_CXX_LANGUAGE_STANDARD = "c++20"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = YES; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = ""; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 15.1; + LD_RUNPATH_SEARCH_PATHS = ( + /usr/lib/swift, + "$(inherited)", + ); + LIBRARY_SEARCH_PATHS = ( + "\"$(SDKROOT)/usr/lib/swift\"", + "\"$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)\"", + "\"$(inherited)\"", + ); + MTL_ENABLE_DEBUG_INFO = NO; + OTHER_CFLAGS = "$(inherited)"; + OTHER_CPLUSPLUSFLAGS = ( + "$(OTHER_CFLAGS)", + "-DFOLLY_NO_CONFIG", + "-DFOLLY_MOBILE=1", + "-DFOLLY_USE_LIBCPP=1", + "-DFOLLY_CFG_NO_COROUTINES=1", + "-DFOLLY_HAVE_CLOCK_GETTIME=1", + ); + REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; + SDKROOT = iphoneos; + USE_HERMES = true; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "ControlledInputExample" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 13B07F941A680F5B00A75B9A /* Debug */, + 13B07F951A680F5B00A75B9A /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "ControlledInputExample" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 83CBBA201A601CBA00E9B192 /* Debug */, + 83CBBA211A601CBA00E9B192 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 83CBB9F71A601CBA00E9B192 /* Project object */; +} diff --git a/example/ios/ControlledInputExample.xcodeproj/xcshareddata/xcschemes/ControlledInputExample.xcscheme b/example/ios/ControlledInputExample.xcodeproj/xcshareddata/xcschemes/ControlledInputExample.xcscheme new file mode 100644 index 0000000..e31833f --- /dev/null +++ b/example/ios/ControlledInputExample.xcodeproj/xcshareddata/xcschemes/ControlledInputExample.xcscheme @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/example/ios/ControlledInputExample.xcworkspace/contents.xcworkspacedata b/example/ios/ControlledInputExample.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..b2685e1 --- /dev/null +++ b/example/ios/ControlledInputExample.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/example/ios/ControlledInputExample/AppDelegate.swift b/example/ios/ControlledInputExample/AppDelegate.swift new file mode 100644 index 0000000..3eec95f --- /dev/null +++ b/example/ios/ControlledInputExample/AppDelegate.swift @@ -0,0 +1,48 @@ +import UIKit +import React +import React_RCTAppDelegate +import ReactAppDependencyProvider + +@main +class AppDelegate: UIResponder, UIApplicationDelegate { + var window: UIWindow? + + var reactNativeDelegate: ReactNativeDelegate? + var reactNativeFactory: RCTReactNativeFactory? + + func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil + ) -> Bool { + let delegate = ReactNativeDelegate() + let factory = RCTReactNativeFactory(delegate: delegate) + delegate.dependencyProvider = RCTAppDependencyProvider() + + reactNativeDelegate = delegate + reactNativeFactory = factory + + window = UIWindow(frame: UIScreen.main.bounds) + + factory.startReactNative( + withModuleName: "ControlledInputExample", + in: window, + launchOptions: launchOptions + ) + + return true + } +} + +class ReactNativeDelegate: RCTDefaultReactNativeFactoryDelegate { + override func sourceURL(for bridge: RCTBridge) -> URL? { + self.bundleURL() + } + + override func bundleURL() -> URL? { +#if DEBUG + RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: "index") +#else + Bundle.main.url(forResource: "main", withExtension: "jsbundle") +#endif + } +} diff --git a/example/ios/ControlledInputExample/Images.xcassets/AppIcon.appiconset/Contents.json b/example/ios/ControlledInputExample/Images.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..8121323 --- /dev/null +++ b/example/ios/ControlledInputExample/Images.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,53 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "20x20" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "20x20" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "29x29" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "29x29" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "40x40" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "40x40" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "60x60" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "60x60" + }, + { + "idiom" : "ios-marketing", + "scale" : "1x", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/example/ios/ControlledInputExample/Images.xcassets/Contents.json b/example/ios/ControlledInputExample/Images.xcassets/Contents.json new file mode 100644 index 0000000..2d92bd5 --- /dev/null +++ b/example/ios/ControlledInputExample/Images.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/example/ios/ControlledInputExample/Info.plist b/example/ios/ControlledInputExample/Info.plist new file mode 100644 index 0000000..15fc7c7 --- /dev/null +++ b/example/ios/ControlledInputExample/Info.plist @@ -0,0 +1,59 @@ + + + + + CADisableMinimumFrameDurationOnPhone + + CFBundleDevelopmentRegion + en + CFBundleDisplayName + ControlledInputExample + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + $(MARKETING_VERSION) + CFBundleSignature + ???? + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + LSRequiresIPhoneOS + + NSAppTransportSecurity + + NSAllowsArbitraryLoads + + NSAllowsLocalNetworking + + + NSLocationWhenInUseUsageDescription + + RCTNewArchEnabled + + UILaunchStoryboardName + LaunchScreen + UIRequiredDeviceCapabilities + + arm64 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UIViewControllerBasedStatusBarAppearance + + UIAppFonts + + AlbertSans-Regular.otf + + + diff --git a/example/ios/ControlledInputExample/LaunchScreen.storyboard b/example/ios/ControlledInputExample/LaunchScreen.storyboard new file mode 100644 index 0000000..e21bf8a --- /dev/null +++ b/example/ios/ControlledInputExample/LaunchScreen.storyboard @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/example/ios/ControlledInputExample/PrivacyInfo.xcprivacy b/example/ios/ControlledInputExample/PrivacyInfo.xcprivacy new file mode 100644 index 0000000..41b8317 --- /dev/null +++ b/example/ios/ControlledInputExample/PrivacyInfo.xcprivacy @@ -0,0 +1,37 @@ + + + + + NSPrivacyAccessedAPITypes + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategoryFileTimestamp + NSPrivacyAccessedAPITypeReasons + + C617.1 + + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategoryUserDefaults + NSPrivacyAccessedAPITypeReasons + + CA92.1 + + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategorySystemBootTime + NSPrivacyAccessedAPITypeReasons + + 35F9.1 + + + + NSPrivacyCollectedDataTypes + + NSPrivacyTracking + + + diff --git a/example/ios/Podfile b/example/ios/Podfile new file mode 100644 index 0000000..33d1793 --- /dev/null +++ b/example/ios/Podfile @@ -0,0 +1,36 @@ +ENV['RCT_NEW_ARCH_ENABLED'] = '1' + +# Resolve react_native_pods.rb with node to allow for hoisting +require Pod::Executable.execute_command('node', ['-p', + 'require.resolve( + "react-native/scripts/react_native_pods.rb", + {paths: [process.argv[1]]}, + )', __dir__]).strip + +platform :ios, min_ios_version_supported +prepare_react_native_project! + +linkage = ENV['USE_FRAMEWORKS'] +if linkage != nil + Pod::UI.puts "Configuring Pod with #{linkage}ally linked Frameworks".green + use_frameworks! :linkage => linkage.to_sym +end + +target 'ControlledInputExample' do + config = use_native_modules! + + use_react_native!( + :path => config[:reactNativePath], + # An absolute path to your application root. + :app_path => "#{Pod::Config.instance.installation_root}/.." + ) + + post_install do |installer| + react_native_post_install( + installer, + config[:reactNativePath], + :mac_catalyst_enabled => false, + # :ccache_enabled => true + ) + end +end diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock new file mode 100644 index 0000000..e36efd8 --- /dev/null +++ b/example/ios/Podfile.lock @@ -0,0 +1,2965 @@ +PODS: + - boost (1.84.0) + - ControlledInput (0.1.0-alpha.1): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTRequired + - RCTTypeSafety + - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-jsi + - React-NativeModulesApple + - React-RCTFabric + - React-renderercss + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - SocketRocket + - Yoga + - DoubleConversion (1.1.6) + - fast_float (8.0.0) + - FBLazyVector (0.83.0) + - fmt (11.0.2) + - glog (0.3.5) + - hermes-engine (0.14.0): + - hermes-engine/Pre-built (= 0.14.0) + - hermes-engine/Pre-built (0.14.0) + - RCT-Folly (2024.11.18.00): + - boost + - DoubleConversion + - fast_float (= 8.0.0) + - fmt (= 11.0.2) + - glog + - RCT-Folly/Default (= 2024.11.18.00) + - RCT-Folly/Default (2024.11.18.00): + - boost + - DoubleConversion + - fast_float (= 8.0.0) + - fmt (= 11.0.2) + - glog + - RCT-Folly/Fabric (2024.11.18.00): + - boost + - DoubleConversion + - fast_float (= 8.0.0) + - fmt (= 11.0.2) + - glog + - RCTDeprecation (0.83.0) + - RCTRequired (0.83.0) + - RCTSwiftUI (0.83.0) + - RCTSwiftUIWrapper (0.83.0): + - RCTSwiftUI + - RCTTypeSafety (0.83.0): + - FBLazyVector (= 0.83.0) + - RCTRequired (= 0.83.0) + - React-Core (= 0.83.0) + - React (0.83.0): + - React-Core (= 0.83.0) + - React-Core/DevSupport (= 0.83.0) + - React-Core/RCTWebSocket (= 0.83.0) + - React-RCTActionSheet (= 0.83.0) + - React-RCTAnimation (= 0.83.0) + - React-RCTBlob (= 0.83.0) + - React-RCTImage (= 0.83.0) + - React-RCTLinking (= 0.83.0) + - React-RCTNetwork (= 0.83.0) + - React-RCTSettings (= 0.83.0) + - React-RCTText (= 0.83.0) + - React-RCTVibration (= 0.83.0) + - React-callinvoker (0.83.0) + - React-Core (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTDeprecation + - React-Core/Default (= 0.83.0) + - React-cxxreact + - React-featureflags + - React-hermes + - React-jsi + - React-jsiexecutor + - React-jsinspector + - React-jsinspectorcdp + - React-jsitooling + - React-perflogger + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - SocketRocket + - Yoga + - React-Core/CoreModulesHeaders (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTDeprecation + - React-Core/Default + - React-cxxreact + - React-featureflags + - React-hermes + - React-jsi + - React-jsiexecutor + - React-jsinspector + - React-jsinspectorcdp + - React-jsitooling + - React-perflogger + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - SocketRocket + - Yoga + - React-Core/Default (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTDeprecation + - React-cxxreact + - React-featureflags + - React-hermes + - React-jsi + - React-jsiexecutor + - React-jsinspector + - React-jsinspectorcdp + - React-jsitooling + - React-perflogger + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - SocketRocket + - Yoga + - React-Core/DevSupport (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTDeprecation + - React-Core/Default (= 0.83.0) + - React-Core/RCTWebSocket (= 0.83.0) + - React-cxxreact + - React-featureflags + - React-hermes + - React-jsi + - React-jsiexecutor + - React-jsinspector + - React-jsinspectorcdp + - React-jsitooling + - React-perflogger + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - SocketRocket + - Yoga + - React-Core/RCTActionSheetHeaders (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTDeprecation + - React-Core/Default + - React-cxxreact + - React-featureflags + - React-hermes + - React-jsi + - React-jsiexecutor + - React-jsinspector + - React-jsinspectorcdp + - React-jsitooling + - React-perflogger + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - SocketRocket + - Yoga + - React-Core/RCTAnimationHeaders (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTDeprecation + - React-Core/Default + - React-cxxreact + - React-featureflags + - React-hermes + - React-jsi + - React-jsiexecutor + - React-jsinspector + - React-jsinspectorcdp + - React-jsitooling + - React-perflogger + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - SocketRocket + - Yoga + - React-Core/RCTBlobHeaders (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTDeprecation + - React-Core/Default + - React-cxxreact + - React-featureflags + - React-hermes + - React-jsi + - React-jsiexecutor + - React-jsinspector + - React-jsinspectorcdp + - React-jsitooling + - React-perflogger + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - SocketRocket + - Yoga + - React-Core/RCTImageHeaders (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTDeprecation + - React-Core/Default + - React-cxxreact + - React-featureflags + - React-hermes + - React-jsi + - React-jsiexecutor + - React-jsinspector + - React-jsinspectorcdp + - React-jsitooling + - React-perflogger + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - SocketRocket + - Yoga + - React-Core/RCTLinkingHeaders (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTDeprecation + - React-Core/Default + - React-cxxreact + - React-featureflags + - React-hermes + - React-jsi + - React-jsiexecutor + - React-jsinspector + - React-jsinspectorcdp + - React-jsitooling + - React-perflogger + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - SocketRocket + - Yoga + - React-Core/RCTNetworkHeaders (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTDeprecation + - React-Core/Default + - React-cxxreact + - React-featureflags + - React-hermes + - React-jsi + - React-jsiexecutor + - React-jsinspector + - React-jsinspectorcdp + - React-jsitooling + - React-perflogger + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - SocketRocket + - Yoga + - React-Core/RCTSettingsHeaders (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTDeprecation + - React-Core/Default + - React-cxxreact + - React-featureflags + - React-hermes + - React-jsi + - React-jsiexecutor + - React-jsinspector + - React-jsinspectorcdp + - React-jsitooling + - React-perflogger + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - SocketRocket + - Yoga + - React-Core/RCTTextHeaders (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTDeprecation + - React-Core/Default + - React-cxxreact + - React-featureflags + - React-hermes + - React-jsi + - React-jsiexecutor + - React-jsinspector + - React-jsinspectorcdp + - React-jsitooling + - React-perflogger + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - SocketRocket + - Yoga + - React-Core/RCTVibrationHeaders (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTDeprecation + - React-Core/Default + - React-cxxreact + - React-featureflags + - React-hermes + - React-jsi + - React-jsiexecutor + - React-jsinspector + - React-jsinspectorcdp + - React-jsitooling + - React-perflogger + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - SocketRocket + - Yoga + - React-Core/RCTWebSocket (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTDeprecation + - React-Core/Default (= 0.83.0) + - React-cxxreact + - React-featureflags + - React-hermes + - React-jsi + - React-jsiexecutor + - React-jsinspector + - React-jsinspectorcdp + - React-jsitooling + - React-perflogger + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - SocketRocket + - Yoga + - React-CoreModules (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - RCT-Folly + - RCT-Folly/Fabric + - RCTTypeSafety (= 0.83.0) + - React-Core/CoreModulesHeaders (= 0.83.0) + - React-debug + - React-jsi (= 0.83.0) + - React-jsinspector + - React-jsinspectorcdp + - React-jsinspectortracing + - React-NativeModulesApple + - React-RCTBlob + - React-RCTFBReactNativeSpec + - React-RCTImage (= 0.83.0) + - React-runtimeexecutor + - React-utils + - ReactCommon + - SocketRocket + - React-cxxreact (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - React-callinvoker (= 0.83.0) + - React-debug (= 0.83.0) + - React-jsi (= 0.83.0) + - React-jsinspector + - React-jsinspectorcdp + - React-jsinspectortracing + - React-logger (= 0.83.0) + - React-perflogger (= 0.83.0) + - React-runtimeexecutor + - React-timing (= 0.83.0) + - React-utils + - SocketRocket + - React-debug (0.83.0) + - React-defaultsnativemodule (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - React-domnativemodule + - React-featureflags + - React-featureflagsnativemodule + - React-idlecallbacksnativemodule + - React-intersectionobservernativemodule + - React-jsi + - React-jsiexecutor + - React-microtasksnativemodule + - React-RCTFBReactNativeSpec + - React-webperformancenativemodule + - SocketRocket + - Yoga + - React-domnativemodule (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - React-Fabric + - React-Fabric/bridging + - React-FabricComponents + - React-graphics + - React-jsi + - React-jsiexecutor + - React-RCTFBReactNativeSpec + - React-runtimeexecutor + - ReactCommon/turbomodule/core + - SocketRocket + - Yoga + - React-Fabric (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-Fabric/animated (= 0.83.0) + - React-Fabric/animationbackend (= 0.83.0) + - React-Fabric/animations (= 0.83.0) + - React-Fabric/attributedstring (= 0.83.0) + - React-Fabric/bridging (= 0.83.0) + - React-Fabric/componentregistry (= 0.83.0) + - React-Fabric/componentregistrynative (= 0.83.0) + - React-Fabric/components (= 0.83.0) + - React-Fabric/consistency (= 0.83.0) + - React-Fabric/core (= 0.83.0) + - React-Fabric/dom (= 0.83.0) + - React-Fabric/imagemanager (= 0.83.0) + - React-Fabric/leakchecker (= 0.83.0) + - React-Fabric/mounting (= 0.83.0) + - React-Fabric/observers (= 0.83.0) + - React-Fabric/scheduler (= 0.83.0) + - React-Fabric/telemetry (= 0.83.0) + - React-Fabric/templateprocessor (= 0.83.0) + - React-Fabric/uimanager (= 0.83.0) + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - SocketRocket + - React-Fabric/animated (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - SocketRocket + - React-Fabric/animationbackend (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - SocketRocket + - React-Fabric/animations (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - SocketRocket + - React-Fabric/attributedstring (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - SocketRocket + - React-Fabric/bridging (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - SocketRocket + - React-Fabric/componentregistry (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - SocketRocket + - React-Fabric/componentregistrynative (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - SocketRocket + - React-Fabric/components (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-Fabric/components/legacyviewmanagerinterop (= 0.83.0) + - React-Fabric/components/root (= 0.83.0) + - React-Fabric/components/scrollview (= 0.83.0) + - React-Fabric/components/view (= 0.83.0) + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - SocketRocket + - React-Fabric/components/legacyviewmanagerinterop (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - SocketRocket + - React-Fabric/components/root (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - SocketRocket + - React-Fabric/components/scrollview (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - SocketRocket + - React-Fabric/components/view (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-renderercss + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - SocketRocket + - Yoga + - React-Fabric/consistency (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - SocketRocket + - React-Fabric/core (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - SocketRocket + - React-Fabric/dom (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - SocketRocket + - React-Fabric/imagemanager (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - SocketRocket + - React-Fabric/leakchecker (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - SocketRocket + - React-Fabric/mounting (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - SocketRocket + - React-Fabric/observers (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-Fabric/observers/events (= 0.83.0) + - React-Fabric/observers/intersection (= 0.83.0) + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - SocketRocket + - React-Fabric/observers/events (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - SocketRocket + - React-Fabric/observers/intersection (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - SocketRocket + - React-Fabric/scheduler (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-Fabric/observers/events + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-performancecdpmetrics + - React-performancetimeline + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - SocketRocket + - React-Fabric/telemetry (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - SocketRocket + - React-Fabric/templateprocessor (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - SocketRocket + - React-Fabric/uimanager (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-Fabric/uimanager/consistency (= 0.83.0) + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererconsistency + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - SocketRocket + - React-Fabric/uimanager/consistency (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererconsistency + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - SocketRocket + - React-FabricComponents (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-Fabric + - React-FabricComponents/components (= 0.83.0) + - React-FabricComponents/textlayoutmanager (= 0.83.0) + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-RCTFBReactNativeSpec + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - SocketRocket + - Yoga + - React-FabricComponents/components (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-Fabric + - React-FabricComponents/components/inputaccessory (= 0.83.0) + - React-FabricComponents/components/iostextinput (= 0.83.0) + - React-FabricComponents/components/modal (= 0.83.0) + - React-FabricComponents/components/rncore (= 0.83.0) + - React-FabricComponents/components/safeareaview (= 0.83.0) + - React-FabricComponents/components/scrollview (= 0.83.0) + - React-FabricComponents/components/switch (= 0.83.0) + - React-FabricComponents/components/text (= 0.83.0) + - React-FabricComponents/components/textinput (= 0.83.0) + - React-FabricComponents/components/unimplementedview (= 0.83.0) + - React-FabricComponents/components/virtualview (= 0.83.0) + - React-FabricComponents/components/virtualviewexperimental (= 0.83.0) + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-RCTFBReactNativeSpec + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - SocketRocket + - Yoga + - React-FabricComponents/components/inputaccessory (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-RCTFBReactNativeSpec + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - SocketRocket + - Yoga + - React-FabricComponents/components/iostextinput (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-RCTFBReactNativeSpec + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - SocketRocket + - Yoga + - React-FabricComponents/components/modal (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-RCTFBReactNativeSpec + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - SocketRocket + - Yoga + - React-FabricComponents/components/rncore (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-RCTFBReactNativeSpec + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - SocketRocket + - Yoga + - React-FabricComponents/components/safeareaview (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-RCTFBReactNativeSpec + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - SocketRocket + - Yoga + - React-FabricComponents/components/scrollview (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-RCTFBReactNativeSpec + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - SocketRocket + - Yoga + - React-FabricComponents/components/switch (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-RCTFBReactNativeSpec + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - SocketRocket + - Yoga + - React-FabricComponents/components/text (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-RCTFBReactNativeSpec + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - SocketRocket + - Yoga + - React-FabricComponents/components/textinput (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-RCTFBReactNativeSpec + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - SocketRocket + - Yoga + - React-FabricComponents/components/unimplementedview (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-RCTFBReactNativeSpec + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - SocketRocket + - Yoga + - React-FabricComponents/components/virtualview (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-RCTFBReactNativeSpec + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - SocketRocket + - Yoga + - React-FabricComponents/components/virtualviewexperimental (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-RCTFBReactNativeSpec + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - SocketRocket + - Yoga + - React-FabricComponents/textlayoutmanager (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-RCTFBReactNativeSpec + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - SocketRocket + - Yoga + - React-FabricImage (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTRequired (= 0.83.0) + - RCTTypeSafety (= 0.83.0) + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-jsi + - React-jsiexecutor (= 0.83.0) + - React-logger + - React-rendererdebug + - React-utils + - ReactCommon + - SocketRocket + - Yoga + - React-featureflags (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - RCT-Folly + - RCT-Folly/Fabric + - SocketRocket + - React-featureflagsnativemodule (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - React-featureflags + - React-jsi + - React-jsiexecutor + - React-RCTFBReactNativeSpec + - ReactCommon/turbomodule/core + - SocketRocket + - React-graphics (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - React-jsi + - React-jsiexecutor + - React-utils + - SocketRocket + - React-hermes (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - React-cxxreact (= 0.83.0) + - React-jsi + - React-jsiexecutor (= 0.83.0) + - React-jsinspector + - React-jsinspectorcdp + - React-jsinspectortracing + - React-oscompat + - React-perflogger (= 0.83.0) + - React-runtimeexecutor + - SocketRocket + - React-idlecallbacksnativemodule (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - React-jsi + - React-jsiexecutor + - React-RCTFBReactNativeSpec + - React-runtimeexecutor + - React-runtimescheduler + - ReactCommon/turbomodule/core + - SocketRocket + - React-ImageManager (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - RCT-Folly + - RCT-Folly/Fabric + - React-Core/Default + - React-debug + - React-Fabric + - React-graphics + - React-rendererdebug + - React-utils + - SocketRocket + - React-intersectionobservernativemodule (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - React-cxxreact + - React-Fabric + - React-Fabric/bridging + - React-graphics + - React-jsi + - React-jsiexecutor + - React-RCTFBReactNativeSpec + - React-runtimeexecutor + - React-runtimescheduler + - ReactCommon/turbomodule/core + - SocketRocket + - Yoga + - React-jserrorhandler (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - React-cxxreact + - React-debug + - React-featureflags + - React-jsi + - ReactCommon/turbomodule/bridging + - SocketRocket + - React-jsi (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - SocketRocket + - React-jsiexecutor (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - React-cxxreact + - React-debug + - React-jsi + - React-jsinspector + - React-jsinspectorcdp + - React-jsinspectortracing + - React-perflogger + - React-runtimeexecutor + - React-utils + - SocketRocket + - React-jsinspector (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - React-featureflags + - React-jsi + - React-jsinspectorcdp + - React-jsinspectornetwork + - React-jsinspectortracing + - React-oscompat + - React-perflogger (= 0.83.0) + - React-runtimeexecutor + - React-utils + - SocketRocket + - React-jsinspectorcdp (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - RCT-Folly + - RCT-Folly/Fabric + - SocketRocket + - React-jsinspectornetwork (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - RCT-Folly + - RCT-Folly/Fabric + - React-jsinspectorcdp + - SocketRocket + - React-jsinspectortracing (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - React-jsi + - React-jsinspectornetwork + - React-oscompat + - React-timing + - SocketRocket + - React-jsitooling (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - RCT-Folly + - RCT-Folly/Fabric + - React-cxxreact (= 0.83.0) + - React-debug + - React-jsi (= 0.83.0) + - React-jsinspector + - React-jsinspectorcdp + - React-jsinspectortracing + - React-runtimeexecutor + - React-utils + - SocketRocket + - React-jsitracing (0.83.0): + - React-jsi + - React-logger (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - RCT-Folly + - RCT-Folly/Fabric + - SocketRocket + - React-Mapbuffer (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - RCT-Folly + - RCT-Folly/Fabric + - React-debug + - SocketRocket + - React-microtasksnativemodule (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - React-jsi + - React-jsiexecutor + - React-RCTFBReactNativeSpec + - ReactCommon/turbomodule/core + - SocketRocket + - react-native-safe-area-context (5.7.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTRequired + - RCTTypeSafety + - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-jsi + - react-native-safe-area-context/common (= 5.7.0) + - react-native-safe-area-context/fabric (= 5.7.0) + - React-NativeModulesApple + - React-RCTFabric + - React-renderercss + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - SocketRocket + - Yoga + - react-native-safe-area-context/common (5.7.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTRequired + - RCTTypeSafety + - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-jsi + - React-NativeModulesApple + - React-RCTFabric + - React-renderercss + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - SocketRocket + - Yoga + - react-native-safe-area-context/fabric (5.7.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTRequired + - RCTTypeSafety + - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-jsi + - react-native-safe-area-context/common + - React-NativeModulesApple + - React-RCTFabric + - React-renderercss + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - SocketRocket + - Yoga + - React-NativeModulesApple (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - React-callinvoker + - React-Core + - React-cxxreact + - React-debug + - React-featureflags + - React-jsi + - React-jsinspector + - React-jsinspectorcdp + - React-runtimeexecutor + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - SocketRocket + - React-networking (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - RCT-Folly + - RCT-Folly/Fabric + - React-featureflags + - React-jsinspectornetwork + - React-jsinspectortracing + - React-performancetimeline + - React-timing + - SocketRocket + - React-oscompat (0.83.0) + - React-perflogger (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - RCT-Folly + - RCT-Folly/Fabric + - SocketRocket + - React-performancecdpmetrics (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - React-jsi + - React-performancetimeline + - React-runtimeexecutor + - React-timing + - SocketRocket + - React-performancetimeline (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - RCT-Folly + - RCT-Folly/Fabric + - React-featureflags + - React-jsinspectortracing + - React-perflogger + - React-timing + - SocketRocket + - React-RCTActionSheet (0.83.0): + - React-Core/RCTActionSheetHeaders (= 0.83.0) + - React-RCTAnimation (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - RCT-Folly + - RCT-Folly/Fabric + - RCTTypeSafety + - React-Core/RCTAnimationHeaders + - React-featureflags + - React-jsi + - React-NativeModulesApple + - React-RCTFBReactNativeSpec + - ReactCommon + - SocketRocket + - React-RCTAppDelegate (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTRequired + - RCTTypeSafety + - React-Core + - React-CoreModules + - React-debug + - React-defaultsnativemodule + - React-Fabric + - React-featureflags + - React-graphics + - React-hermes + - React-jsitooling + - React-NativeModulesApple + - React-RCTFabric + - React-RCTFBReactNativeSpec + - React-RCTImage + - React-RCTNetwork + - React-RCTRuntime + - React-rendererdebug + - React-RuntimeApple + - React-RuntimeCore + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon + - SocketRocket + - React-RCTBlob (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - React-Core/RCTBlobHeaders + - React-Core/RCTWebSocket + - React-jsi + - React-jsinspector + - React-jsinspectorcdp + - React-NativeModulesApple + - React-RCTFBReactNativeSpec + - React-RCTNetwork + - ReactCommon + - SocketRocket + - React-RCTFabric (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTSwiftUIWrapper + - React-Core + - React-debug + - React-Fabric + - React-FabricComponents + - React-FabricImage + - React-featureflags + - React-graphics + - React-ImageManager + - React-jsi + - React-jsinspector + - React-jsinspectorcdp + - React-jsinspectortracing + - React-networking + - React-performancecdpmetrics + - React-performancetimeline + - React-RCTAnimation + - React-RCTFBReactNativeSpec + - React-RCTImage + - React-RCTText + - React-rendererconsistency + - React-renderercss + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - SocketRocket + - Yoga + - React-RCTFBReactNativeSpec (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTRequired + - RCTTypeSafety + - React-Core + - React-jsi + - React-NativeModulesApple + - React-RCTFBReactNativeSpec/components (= 0.83.0) + - ReactCommon + - SocketRocket + - React-RCTFBReactNativeSpec/components (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTRequired + - RCTTypeSafety + - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-jsi + - React-NativeModulesApple + - React-rendererdebug + - React-utils + - ReactCommon + - SocketRocket + - Yoga + - React-RCTImage (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - RCT-Folly + - RCT-Folly/Fabric + - RCTTypeSafety + - React-Core/RCTImageHeaders + - React-jsi + - React-NativeModulesApple + - React-RCTFBReactNativeSpec + - React-RCTNetwork + - ReactCommon + - SocketRocket + - React-RCTLinking (0.83.0): + - React-Core/RCTLinkingHeaders (= 0.83.0) + - React-jsi (= 0.83.0) + - React-NativeModulesApple + - React-RCTFBReactNativeSpec + - ReactCommon + - ReactCommon/turbomodule/core (= 0.83.0) + - React-RCTNetwork (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - RCT-Folly + - RCT-Folly/Fabric + - RCTTypeSafety + - React-Core/RCTNetworkHeaders + - React-debug + - React-featureflags + - React-jsi + - React-jsinspectorcdp + - React-jsinspectornetwork + - React-NativeModulesApple + - React-networking + - React-RCTFBReactNativeSpec + - ReactCommon + - SocketRocket + - React-RCTRuntime (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - React-Core + - React-debug + - React-jsi + - React-jsinspector + - React-jsinspectorcdp + - React-jsinspectortracing + - React-jsitooling + - React-RuntimeApple + - React-RuntimeCore + - React-runtimeexecutor + - React-RuntimeHermes + - React-utils + - SocketRocket + - React-RCTSettings (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - RCT-Folly + - RCT-Folly/Fabric + - RCTTypeSafety + - React-Core/RCTSettingsHeaders + - React-jsi + - React-NativeModulesApple + - React-RCTFBReactNativeSpec + - ReactCommon + - SocketRocket + - React-RCTText (0.83.0): + - React-Core/RCTTextHeaders (= 0.83.0) + - Yoga + - React-RCTVibration (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - RCT-Folly + - RCT-Folly/Fabric + - React-Core/RCTVibrationHeaders + - React-jsi + - React-NativeModulesApple + - React-RCTFBReactNativeSpec + - ReactCommon + - SocketRocket + - React-rendererconsistency (0.83.0) + - React-renderercss (0.83.0): + - React-debug + - React-utils + - React-rendererdebug (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - RCT-Folly + - RCT-Folly/Fabric + - React-debug + - SocketRocket + - React-RuntimeApple (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - React-callinvoker + - React-Core/Default + - React-CoreModules + - React-cxxreact + - React-featureflags + - React-jserrorhandler + - React-jsi + - React-jsiexecutor + - React-jsinspector + - React-jsitooling + - React-Mapbuffer + - React-NativeModulesApple + - React-RCTFabric + - React-RCTFBReactNativeSpec + - React-RuntimeCore + - React-runtimeexecutor + - React-RuntimeHermes + - React-runtimescheduler + - React-utils + - SocketRocket + - React-RuntimeCore (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - React-cxxreact + - React-Fabric + - React-featureflags + - React-jserrorhandler + - React-jsi + - React-jsiexecutor + - React-jsinspector + - React-jsitooling + - React-performancetimeline + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - SocketRocket + - React-runtimeexecutor (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - RCT-Folly + - RCT-Folly/Fabric + - React-debug + - React-featureflags + - React-jsi (= 0.83.0) + - React-utils + - SocketRocket + - React-RuntimeHermes (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - React-featureflags + - React-hermes + - React-jsi + - React-jsinspector + - React-jsinspectorcdp + - React-jsinspectortracing + - React-jsitooling + - React-jsitracing + - React-RuntimeCore + - React-runtimeexecutor + - React-utils + - SocketRocket + - React-runtimescheduler (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - React-callinvoker + - React-cxxreact + - React-debug + - React-featureflags + - React-jsi + - React-jsinspectortracing + - React-performancetimeline + - React-rendererconsistency + - React-rendererdebug + - React-runtimeexecutor + - React-timing + - React-utils + - SocketRocket + - React-timing (0.83.0): + - React-debug + - React-utils (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - React-debug + - React-jsi (= 0.83.0) + - SocketRocket + - React-webperformancenativemodule (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - React-cxxreact + - React-jsi + - React-jsiexecutor + - React-performancetimeline + - React-RCTFBReactNativeSpec + - React-runtimeexecutor + - ReactCommon/turbomodule/core + - SocketRocket + - ReactAppDependencyProvider (0.83.0): + - ReactCodegen + - ReactCodegen (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTRequired + - RCTTypeSafety + - React-Core + - React-debug + - React-Fabric + - React-FabricImage + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-NativeModulesApple + - React-RCTAppDelegate + - React-rendererdebug + - React-utils + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - SocketRocket + - ReactCommon (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - RCT-Folly + - RCT-Folly/Fabric + - ReactCommon/turbomodule (= 0.83.0) + - SocketRocket + - ReactCommon/turbomodule (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - React-callinvoker (= 0.83.0) + - React-cxxreact (= 0.83.0) + - React-jsi (= 0.83.0) + - React-logger (= 0.83.0) + - React-perflogger (= 0.83.0) + - ReactCommon/turbomodule/bridging (= 0.83.0) + - ReactCommon/turbomodule/core (= 0.83.0) + - SocketRocket + - ReactCommon/turbomodule/bridging (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - React-callinvoker (= 0.83.0) + - React-cxxreact (= 0.83.0) + - React-jsi (= 0.83.0) + - React-logger (= 0.83.0) + - React-perflogger (= 0.83.0) + - SocketRocket + - ReactCommon/turbomodule/core (0.83.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - React-callinvoker (= 0.83.0) + - React-cxxreact (= 0.83.0) + - React-debug (= 0.83.0) + - React-featureflags (= 0.83.0) + - React-jsi (= 0.83.0) + - React-logger (= 0.83.0) + - React-perflogger (= 0.83.0) + - React-utils (= 0.83.0) + - SocketRocket + - RNScreens (4.24.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTRequired + - RCTTypeSafety + - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-jsi + - React-NativeModulesApple + - React-RCTFabric + - React-RCTImage + - React-renderercss + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - RNScreens/common (= 4.24.0) + - SocketRocket + - Yoga + - RNScreens/common (4.24.0): + - boost + - DoubleConversion + - fast_float + - fmt + - glog + - hermes-engine + - RCT-Folly + - RCT-Folly/Fabric + - RCTRequired + - RCTTypeSafety + - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-jsi + - React-NativeModulesApple + - React-RCTFabric + - React-RCTImage + - React-renderercss + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - SocketRocket + - Yoga + - SocketRocket (0.7.1) + - Yoga (0.0.0) + +DEPENDENCIES: + - boost (from `../node_modules/react-native/third-party-podspecs/boost.podspec`) + - ControlledInput (from `../..`) + - DoubleConversion (from `../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`) + - fast_float (from `../node_modules/react-native/third-party-podspecs/fast_float.podspec`) + - FBLazyVector (from `../node_modules/react-native/Libraries/FBLazyVector`) + - fmt (from `../node_modules/react-native/third-party-podspecs/fmt.podspec`) + - glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`) + - hermes-engine (from `../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec`) + - RCT-Folly (from `../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec`) + - RCTDeprecation (from `../node_modules/react-native/ReactApple/Libraries/RCTFoundation/RCTDeprecation`) + - RCTRequired (from `../node_modules/react-native/Libraries/Required`) + - RCTSwiftUI (from `../node_modules/react-native/ReactApple/RCTSwiftUI`) + - RCTSwiftUIWrapper (from `../node_modules/react-native/ReactApple/RCTSwiftUIWrapper`) + - RCTTypeSafety (from `../node_modules/react-native/Libraries/TypeSafety`) + - React (from `../node_modules/react-native/`) + - React-callinvoker (from `../node_modules/react-native/ReactCommon/callinvoker`) + - React-Core (from `../node_modules/react-native/`) + - React-Core/RCTWebSocket (from `../node_modules/react-native/`) + - React-CoreModules (from `../node_modules/react-native/React/CoreModules`) + - React-cxxreact (from `../node_modules/react-native/ReactCommon/cxxreact`) + - React-debug (from `../node_modules/react-native/ReactCommon/react/debug`) + - React-defaultsnativemodule (from `../node_modules/react-native/ReactCommon/react/nativemodule/defaults`) + - React-domnativemodule (from `../node_modules/react-native/ReactCommon/react/nativemodule/dom`) + - React-Fabric (from `../node_modules/react-native/ReactCommon`) + - React-FabricComponents (from `../node_modules/react-native/ReactCommon`) + - React-FabricImage (from `../node_modules/react-native/ReactCommon`) + - React-featureflags (from `../node_modules/react-native/ReactCommon/react/featureflags`) + - React-featureflagsnativemodule (from `../node_modules/react-native/ReactCommon/react/nativemodule/featureflags`) + - React-graphics (from `../node_modules/react-native/ReactCommon/react/renderer/graphics`) + - React-hermes (from `../node_modules/react-native/ReactCommon/hermes`) + - React-idlecallbacksnativemodule (from `../node_modules/react-native/ReactCommon/react/nativemodule/idlecallbacks`) + - React-ImageManager (from `../node_modules/react-native/ReactCommon/react/renderer/imagemanager/platform/ios`) + - React-intersectionobservernativemodule (from `../node_modules/react-native/ReactCommon/react/nativemodule/intersectionobserver`) + - React-jserrorhandler (from `../node_modules/react-native/ReactCommon/jserrorhandler`) + - React-jsi (from `../node_modules/react-native/ReactCommon/jsi`) + - React-jsiexecutor (from `../node_modules/react-native/ReactCommon/jsiexecutor`) + - React-jsinspector (from `../node_modules/react-native/ReactCommon/jsinspector-modern`) + - React-jsinspectorcdp (from `../node_modules/react-native/ReactCommon/jsinspector-modern/cdp`) + - React-jsinspectornetwork (from `../node_modules/react-native/ReactCommon/jsinspector-modern/network`) + - React-jsinspectortracing (from `../node_modules/react-native/ReactCommon/jsinspector-modern/tracing`) + - React-jsitooling (from `../node_modules/react-native/ReactCommon/jsitooling`) + - React-jsitracing (from `../node_modules/react-native/ReactCommon/hermes/executor/`) + - React-logger (from `../node_modules/react-native/ReactCommon/logger`) + - React-Mapbuffer (from `../node_modules/react-native/ReactCommon`) + - React-microtasksnativemodule (from `../node_modules/react-native/ReactCommon/react/nativemodule/microtasks`) + - react-native-safe-area-context (from `../node_modules/react-native-safe-area-context`) + - React-NativeModulesApple (from `../node_modules/react-native/ReactCommon/react/nativemodule/core/platform/ios`) + - React-networking (from `../node_modules/react-native/ReactCommon/react/networking`) + - React-oscompat (from `../node_modules/react-native/ReactCommon/oscompat`) + - React-perflogger (from `../node_modules/react-native/ReactCommon/reactperflogger`) + - React-performancecdpmetrics (from `../node_modules/react-native/ReactCommon/react/performance/cdpmetrics`) + - React-performancetimeline (from `../node_modules/react-native/ReactCommon/react/performance/timeline`) + - React-RCTActionSheet (from `../node_modules/react-native/Libraries/ActionSheetIOS`) + - React-RCTAnimation (from `../node_modules/react-native/Libraries/NativeAnimation`) + - React-RCTAppDelegate (from `../node_modules/react-native/Libraries/AppDelegate`) + - React-RCTBlob (from `../node_modules/react-native/Libraries/Blob`) + - React-RCTFabric (from `../node_modules/react-native/React`) + - React-RCTFBReactNativeSpec (from `../node_modules/react-native/React`) + - React-RCTImage (from `../node_modules/react-native/Libraries/Image`) + - React-RCTLinking (from `../node_modules/react-native/Libraries/LinkingIOS`) + - React-RCTNetwork (from `../node_modules/react-native/Libraries/Network`) + - React-RCTRuntime (from `../node_modules/react-native/React/Runtime`) + - React-RCTSettings (from `../node_modules/react-native/Libraries/Settings`) + - React-RCTText (from `../node_modules/react-native/Libraries/Text`) + - React-RCTVibration (from `../node_modules/react-native/Libraries/Vibration`) + - React-rendererconsistency (from `../node_modules/react-native/ReactCommon/react/renderer/consistency`) + - React-renderercss (from `../node_modules/react-native/ReactCommon/react/renderer/css`) + - React-rendererdebug (from `../node_modules/react-native/ReactCommon/react/renderer/debug`) + - React-RuntimeApple (from `../node_modules/react-native/ReactCommon/react/runtime/platform/ios`) + - React-RuntimeCore (from `../node_modules/react-native/ReactCommon/react/runtime`) + - React-runtimeexecutor (from `../node_modules/react-native/ReactCommon/runtimeexecutor`) + - React-RuntimeHermes (from `../node_modules/react-native/ReactCommon/react/runtime`) + - React-runtimescheduler (from `../node_modules/react-native/ReactCommon/react/renderer/runtimescheduler`) + - React-timing (from `../node_modules/react-native/ReactCommon/react/timing`) + - React-utils (from `../node_modules/react-native/ReactCommon/react/utils`) + - React-webperformancenativemodule (from `../node_modules/react-native/ReactCommon/react/nativemodule/webperformance`) + - ReactAppDependencyProvider (from `build/generated/ios/ReactAppDependencyProvider`) + - ReactCodegen (from `build/generated/ios/ReactCodegen`) + - ReactCommon/turbomodule/core (from `../node_modules/react-native/ReactCommon`) + - RNScreens (from `../node_modules/react-native-screens`) + - SocketRocket (~> 0.7.1) + - Yoga (from `../node_modules/react-native/ReactCommon/yoga`) + +SPEC REPOS: + trunk: + - SocketRocket + +EXTERNAL SOURCES: + boost: + :podspec: "../node_modules/react-native/third-party-podspecs/boost.podspec" + ControlledInput: + :path: "../.." + DoubleConversion: + :podspec: "../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec" + fast_float: + :podspec: "../node_modules/react-native/third-party-podspecs/fast_float.podspec" + FBLazyVector: + :path: "../node_modules/react-native/Libraries/FBLazyVector" + fmt: + :podspec: "../node_modules/react-native/third-party-podspecs/fmt.podspec" + glog: + :podspec: "../node_modules/react-native/third-party-podspecs/glog.podspec" + hermes-engine: + :podspec: "../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec" + :tag: hermes-v0.14.0 + RCT-Folly: + :podspec: "../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec" + RCTDeprecation: + :path: "../node_modules/react-native/ReactApple/Libraries/RCTFoundation/RCTDeprecation" + RCTRequired: + :path: "../node_modules/react-native/Libraries/Required" + RCTSwiftUI: + :path: "../node_modules/react-native/ReactApple/RCTSwiftUI" + RCTSwiftUIWrapper: + :path: "../node_modules/react-native/ReactApple/RCTSwiftUIWrapper" + RCTTypeSafety: + :path: "../node_modules/react-native/Libraries/TypeSafety" + React: + :path: "../node_modules/react-native/" + React-callinvoker: + :path: "../node_modules/react-native/ReactCommon/callinvoker" + React-Core: + :path: "../node_modules/react-native/" + React-CoreModules: + :path: "../node_modules/react-native/React/CoreModules" + React-cxxreact: + :path: "../node_modules/react-native/ReactCommon/cxxreact" + React-debug: + :path: "../node_modules/react-native/ReactCommon/react/debug" + React-defaultsnativemodule: + :path: "../node_modules/react-native/ReactCommon/react/nativemodule/defaults" + React-domnativemodule: + :path: "../node_modules/react-native/ReactCommon/react/nativemodule/dom" + React-Fabric: + :path: "../node_modules/react-native/ReactCommon" + React-FabricComponents: + :path: "../node_modules/react-native/ReactCommon" + React-FabricImage: + :path: "../node_modules/react-native/ReactCommon" + React-featureflags: + :path: "../node_modules/react-native/ReactCommon/react/featureflags" + React-featureflagsnativemodule: + :path: "../node_modules/react-native/ReactCommon/react/nativemodule/featureflags" + React-graphics: + :path: "../node_modules/react-native/ReactCommon/react/renderer/graphics" + React-hermes: + :path: "../node_modules/react-native/ReactCommon/hermes" + React-idlecallbacksnativemodule: + :path: "../node_modules/react-native/ReactCommon/react/nativemodule/idlecallbacks" + React-ImageManager: + :path: "../node_modules/react-native/ReactCommon/react/renderer/imagemanager/platform/ios" + React-intersectionobservernativemodule: + :path: "../node_modules/react-native/ReactCommon/react/nativemodule/intersectionobserver" + React-jserrorhandler: + :path: "../node_modules/react-native/ReactCommon/jserrorhandler" + React-jsi: + :path: "../node_modules/react-native/ReactCommon/jsi" + React-jsiexecutor: + :path: "../node_modules/react-native/ReactCommon/jsiexecutor" + React-jsinspector: + :path: "../node_modules/react-native/ReactCommon/jsinspector-modern" + React-jsinspectorcdp: + :path: "../node_modules/react-native/ReactCommon/jsinspector-modern/cdp" + React-jsinspectornetwork: + :path: "../node_modules/react-native/ReactCommon/jsinspector-modern/network" + React-jsinspectortracing: + :path: "../node_modules/react-native/ReactCommon/jsinspector-modern/tracing" + React-jsitooling: + :path: "../node_modules/react-native/ReactCommon/jsitooling" + React-jsitracing: + :path: "../node_modules/react-native/ReactCommon/hermes/executor/" + React-logger: + :path: "../node_modules/react-native/ReactCommon/logger" + React-Mapbuffer: + :path: "../node_modules/react-native/ReactCommon" + React-microtasksnativemodule: + :path: "../node_modules/react-native/ReactCommon/react/nativemodule/microtasks" + react-native-safe-area-context: + :path: "../node_modules/react-native-safe-area-context" + React-NativeModulesApple: + :path: "../node_modules/react-native/ReactCommon/react/nativemodule/core/platform/ios" + React-networking: + :path: "../node_modules/react-native/ReactCommon/react/networking" + React-oscompat: + :path: "../node_modules/react-native/ReactCommon/oscompat" + React-perflogger: + :path: "../node_modules/react-native/ReactCommon/reactperflogger" + React-performancecdpmetrics: + :path: "../node_modules/react-native/ReactCommon/react/performance/cdpmetrics" + React-performancetimeline: + :path: "../node_modules/react-native/ReactCommon/react/performance/timeline" + React-RCTActionSheet: + :path: "../node_modules/react-native/Libraries/ActionSheetIOS" + React-RCTAnimation: + :path: "../node_modules/react-native/Libraries/NativeAnimation" + React-RCTAppDelegate: + :path: "../node_modules/react-native/Libraries/AppDelegate" + React-RCTBlob: + :path: "../node_modules/react-native/Libraries/Blob" + React-RCTFabric: + :path: "../node_modules/react-native/React" + React-RCTFBReactNativeSpec: + :path: "../node_modules/react-native/React" + React-RCTImage: + :path: "../node_modules/react-native/Libraries/Image" + React-RCTLinking: + :path: "../node_modules/react-native/Libraries/LinkingIOS" + React-RCTNetwork: + :path: "../node_modules/react-native/Libraries/Network" + React-RCTRuntime: + :path: "../node_modules/react-native/React/Runtime" + React-RCTSettings: + :path: "../node_modules/react-native/Libraries/Settings" + React-RCTText: + :path: "../node_modules/react-native/Libraries/Text" + React-RCTVibration: + :path: "../node_modules/react-native/Libraries/Vibration" + React-rendererconsistency: + :path: "../node_modules/react-native/ReactCommon/react/renderer/consistency" + React-renderercss: + :path: "../node_modules/react-native/ReactCommon/react/renderer/css" + React-rendererdebug: + :path: "../node_modules/react-native/ReactCommon/react/renderer/debug" + React-RuntimeApple: + :path: "../node_modules/react-native/ReactCommon/react/runtime/platform/ios" + React-RuntimeCore: + :path: "../node_modules/react-native/ReactCommon/react/runtime" + React-runtimeexecutor: + :path: "../node_modules/react-native/ReactCommon/runtimeexecutor" + React-RuntimeHermes: + :path: "../node_modules/react-native/ReactCommon/react/runtime" + React-runtimescheduler: + :path: "../node_modules/react-native/ReactCommon/react/renderer/runtimescheduler" + React-timing: + :path: "../node_modules/react-native/ReactCommon/react/timing" + React-utils: + :path: "../node_modules/react-native/ReactCommon/react/utils" + React-webperformancenativemodule: + :path: "../node_modules/react-native/ReactCommon/react/nativemodule/webperformance" + ReactAppDependencyProvider: + :path: build/generated/ios/ReactAppDependencyProvider + ReactCodegen: + :path: build/generated/ios/ReactCodegen + ReactCommon: + :path: "../node_modules/react-native/ReactCommon" + RNScreens: + :path: "../node_modules/react-native-screens" + Yoga: + :path: "../node_modules/react-native/ReactCommon/yoga" + +SPEC CHECKSUMS: + boost: 7e761d76ca2ce687f7cc98e698152abd03a18f90 + ControlledInput: 309c07cc86b3f6cd453a07c176047609c2e5f1d3 + DoubleConversion: cb417026b2400c8f53ae97020b2be961b59470cb + fast_float: b32c788ed9c6a8c584d114d0047beda9664e7cc6 + FBLazyVector: a293a88992c4c33f0aee184acab0b64a08ff9458 + fmt: a40bb5bd0294ea969aaaba240a927bd33d878cdd + glog: 5683914934d5b6e4240e497e0f4a3b42d1854183 + hermes-engine: b8637df947bb85dd985adc555a4fc124ce7e636a + RCT-Folly: 846fda9475e61ec7bcbf8a3fe81edfcaeb090669 + RCTDeprecation: 2b70c6e3abe00396cefd8913efbf6a2db01a2b36 + RCTRequired: f3540eee8094231581d40c5c6d41b0f170237a81 + RCTSwiftUI: 5928f7ca7e9e2f1a82d85d4c79ea3065137ad81c + RCTSwiftUIWrapper: 8ff2f9da84b47db66d11ece1589d8e5515c0ab8b + RCTTypeSafety: 6359ff3fcbe18c52059f4d4ce301e47f9da5f0d5 + React: f6f8fc5c01e77349cdfaf49102bcb928ac31d8ed + React-callinvoker: 032b6d1d03654b9fb7de9e2b3b978d3cb1a893ad + React-Core: 418c9278f8a071b44a88a87be9a4943234cc2e77 + React-CoreModules: 925b8cb677649f967f6000f9b1ef74dc4ff60c30 + React-cxxreact: 21f6f0cb2a7d26fbed4d09e04482e5c75662beaf + React-debug: 8fc21f2fecd3d6244e988dc55d60cb117d122588 + React-defaultsnativemodule: 05c6115a2d3a7f4a2cc3f96022261570700dbfa5 + React-domnativemodule: f19d7fd59facf19a4e6cb75bf48357c329acaea7 + React-Fabric: 94acdbc0b889bdcec2d5b1a90ae48f1032c5a5a1 + React-FabricComponents: 9754fb783979b88fb82ed3d0c50ae5f5d775a86f + React-FabricImage: d8f5bcb5006eafc0e2262c11bf4dedaa610fd66c + React-featureflags: 8bd4abaf8adf3cf5cc115f128e8761fd3d95b848 + React-featureflagsnativemodule: 0062ca1dc92cb5aae22df8aed4e8f261759cb3bd + React-graphics: 318048b8f98e040c093adcb77ffeb46d78961c30 + React-hermes: 05ca52f53557a31b8ef8bac8f94c3f9db1ff00ed + React-idlecallbacksnativemodule: d3c5ba0150555ce9b7db85008aeb170a02bbf2d8 + React-ImageManager: 225b19fcb16fd353851d664c344025a6d4d79870 + React-intersectionobservernativemodule: d490ebd28572754dfdad4a8d0771573345b1ec92 + React-jserrorhandler: caafb9c1d42c24422829e71e8178de3dd1c7ea12 + React-jsi: 749de748ad3b760011255326c63bf7b7dd6f8f9d + React-jsiexecutor: 02a5ee45bffcae98197eaa253fbf13b65c95073d + React-jsinspector: 4a031b0605009d4bcd079c99df85eb55d142cd12 + React-jsinspectorcdp: 6d25166ec876053b7b6e290eb57f41a9f9496846 + React-jsinspectornetwork: 5c481d208eade7a338f545b2645a2cf134fdf265 + React-jsinspectortracing: b4d2404ecd64a0dd65e2746d9867fbc3a7cd0927 + React-jsitooling: e0d93e78a5a231e4089459ddbed8d4844be9e238 + React-jsitracing: f3c4aae144b86799e9e23eb5ef16bae6b474d4e2 + React-logger: 9e597cbeda7b8cc8aa8fb93860dade97190f69cc + React-Mapbuffer: 20046c0447efaa7aace0b76085aa9bb35b0e8105 + React-microtasksnativemodule: 0e837de56519c92d8a2e3097717df9497feb33cb + react-native-safe-area-context: befb5404eb8a16fdc07fa2bebab3568ecabcbb8a + React-NativeModulesApple: 1a378198515f8e825c5931a7613e98da69320cee + React-networking: bfd1695ada5a57023006ce05823ac5391c3ce072 + React-oscompat: aedc0afbded67280de6bb6bfac8cfde0389e2b33 + React-perflogger: c174462de00c0b7d768f0b2d61b8e2240717a667 + React-performancecdpmetrics: 2607a034407d55049f1820b7ec86db1efd3d22e1 + React-performancetimeline: 6ebdcdf745dbe372508ad7164e732362e7eeae6f + React-RCTActionSheet: 175c74d343e92793d3187b3a819d565f534e0b1d + React-RCTAnimation: d67919cddb7da39c949b8010b4fd4ea39815fe4e + React-RCTAppDelegate: 5f7b1e4b7ee5a44faf5f9518a7d3cabafb801adf + React-RCTBlob: 7ceb93e0918511163f036cfd295973f132a2bc57 + React-RCTFabric: f2250d34e1143c659b845af7e369b3f8f015950c + React-RCTFBReactNativeSpec: b0fc0c9c8adaf8b9183f9e9fb5455ca5deedc7a0 + React-RCTImage: d6297035168312fc3089f8ca0ee7a75216f21715 + React-RCTLinking: 619a2553c4ef83acaccfb551ada1b7d45cf1cce3 + React-RCTNetwork: 7df41788a194dc5b628f58db6a765224b6b37eac + React-RCTRuntime: f75ec08d991c611f1d74154dfeb852e30b1825dd + React-RCTSettings: fa7882ce3d73f1e3482fe05f9cb3167a35a60869 + React-RCTText: 4d659598d9b7730343d465c43d97b3f4aad13938 + React-RCTVibration: 968c3184bfe5005bedd86c913a3b52438222e3a4 + React-rendererconsistency: 1204c62facf6168b69bc5022e0020f19c92f138e + React-renderercss: 36c02a3c55402fdb06226c2ef04d82fc06c4e2fc + React-rendererdebug: 11b54233498d961d939d2f2ec6c640d44efa3c12 + React-RuntimeApple: 5287d92680f4b08c8e882afe9791a41eab69d4a7 + React-RuntimeCore: 402b658d8e9cefb44824624e39a0804f2237e205 + React-runtimeexecutor: a1ce75c4e153ede11be957ef31bb72eef9cc4daf + React-RuntimeHermes: c987b19a1284c685062d3eaad79fd9300a3aa82f + React-runtimescheduler: a12722da46f562626f5897edf9b8fa02219de065 + React-timing: a453a65192dbe400d61d299024e95a302e726661 + React-utils: 43479e74f806f6633ee04c212c48811530041170 + React-webperformancenativemodule: bd1ad71ea9e217e55f66233e99d02581ee3d5cb7 + ReactAppDependencyProvider: ebcf3a78dc1bcdf054c9e8d309244bade6b31568 + ReactCodegen: 11c08ff43a62009d48c71de000352e4515918801 + ReactCommon: 424cc34cf5055d69a3dcf02f3436481afb8b0f6f + RNScreens: 7f643ee0fd1407dc5085c7795460bd93da113b8f + SocketRocket: d4aabe649be1e368d1318fdf28a022d714d65748 + Yoga: 6ca93c8c13f56baeec55eb608577619b17a4d64e + +PODFILE CHECKSUM: 6cca853f65f19607b7e814ae0a0fd0e544fd3d5d + +COCOAPODS: 1.16.2 diff --git a/example/ios/link-assets-manifest.json b/example/ios/link-assets-manifest.json new file mode 100644 index 0000000..05ce0a7 --- /dev/null +++ b/example/ios/link-assets-manifest.json @@ -0,0 +1,9 @@ +{ + "migIndex": 1, + "data": [ + { + "path": "assets/fonts/AlbertSans-Regular.otf", + "sha1": "b8531ef6d9af4a5909ab4bdb1538476e5dc28284" + } + ] +} \ No newline at end of file diff --git a/example/jest.config.js b/example/jest.config.js new file mode 100644 index 0000000..8eb675e --- /dev/null +++ b/example/jest.config.js @@ -0,0 +1,3 @@ +module.exports = { + preset: 'react-native', +}; diff --git a/example/metro.config.js b/example/metro.config.js new file mode 100644 index 0000000..2da198e --- /dev/null +++ b/example/metro.config.js @@ -0,0 +1,16 @@ +const path = require('path'); +const { getDefaultConfig } = require('@react-native/metro-config'); +const { withMetroConfig } = require('react-native-monorepo-config'); + +const root = path.resolve(__dirname, '..'); + +/** + * Metro configuration + * https://facebook.github.io/metro/docs/configuration + * + * @type {import('metro-config').MetroConfig} + */ +module.exports = withMetroConfig(getDefaultConfig(__dirname), { + root, + dirname: __dirname, +}); diff --git a/example/package.json b/example/package.json new file mode 100644 index 0000000..2d0ff65 --- /dev/null +++ b/example/package.json @@ -0,0 +1,37 @@ +{ + "name": "react-native-controlled-input-example", + "version": "0.0.1", + "private": true, + "scripts": { + "android": "react-native run-android", + "ios": "react-native run-ios", + "start": "react-native start", + "build:android": "react-native build-android --extra-params \"--no-daemon --console=plain -PreactNativeArchitectures=arm64-v8a\"", + "build:ios": "react-native build-ios --mode Debug" + }, + "dependencies": { + "@react-navigation/bottom-tabs": "^7.15.9", + "@react-navigation/native": "^7.2.2", + "react": "19.2.0", + "react-native": "0.83.0", + "react-native-safe-area-context": "^5.7.0", + "react-native-screens": "^4.24.0" + }, + "devDependencies": { + "@babel/core": "^7.25.2", + "@babel/preset-env": "^7.25.3", + "@babel/runtime": "^7.25.0", + "@react-native-community/cli": "20.0.0", + "@react-native-community/cli-platform-android": "20.0.0", + "@react-native-community/cli-platform-ios": "20.0.0", + "@react-native/babel-preset": "0.83.0", + "@react-native/metro-config": "0.83.0", + "@react-native/typescript-config": "0.83.0", + "@types/react": "^19.2.0", + "react-native-builder-bob": "^0.40.17", + "react-native-monorepo-config": "^0.3.1" + }, + "engines": { + "node": ">=20" + } +} diff --git a/example/react-native.config.js b/example/react-native.config.js new file mode 100644 index 0000000..f2fcbac --- /dev/null +++ b/example/react-native.config.js @@ -0,0 +1,22 @@ +const path = require('path'); +const pkg = require('../package.json'); + +module.exports = { + project: { + ios: { + automaticPodsInstallation: true, + }, + }, + dependencies: { + [pkg.name]: { + root: path.join(__dirname, '..'), + platforms: { + // Codegen script incorrectly fails without this + // So we explicitly specify the platforms with empty object + ios: {}, + android: {}, + }, + }, + }, + assets: ['./assets/fonts/'], +}; diff --git a/example/src/App.tsx b/example/src/App.tsx new file mode 100644 index 0000000..68f8da8 --- /dev/null +++ b/example/src/App.tsx @@ -0,0 +1,197 @@ +import { + ControlledInputView, + type ControlledInputViewRef, +} from '@ronas-it/react-native-controlled-input'; +import { useRef, useState, type ReactElement } from 'react'; +import { StyleSheet, ScrollView, Button, View } from 'react-native'; + +const formatPromoCode = (input: string): string => { + let letters = ''; + let digits = ''; + + for (const ch of input.toUpperCase()) { + if (/[A-Z]/.test(ch) && letters.length < 4) { + letters += ch; + } else if (/[0-9]/.test(ch) && letters.length === 4 && digits.length < 4) { + digits += ch; + } + } + + if (!digits.length) { + return letters; + } + + return `${letters}-${digits}`; +}; + +const formatExpiry = (input: string): string => { + const raw = input.replace(/\D/g, ''); + let digits = ''; + + for (let i = 0; i < raw.length && digits.length < 4; i++) { + const next = digits + raw[i]; + + if (next.length <= 2) { + const m = next; + + if (m.length === 1) { + if (m !== '0' && m !== '1') { + continue; + } + } else if (Number(m) < 1 || Number(m) > 12) { + continue; + } + } + + digits = next; + } + + if (!digits.length) { + return ''; + } + + const month = digits.slice(0, 2); + const year = digits.slice(2, 4); + + return year ? `${month}/${year}` : month; +}; + +const formatPhone = (input: string): string => { + const digits = input.replace(/\D/g, '').slice(0, 11); + + if (!digits.length) { + return input.includes('+') ? '+' : ''; + } + + let result = `+${digits[0]}`; + + if (digits.length > 1) result += ` (${digits.slice(1, 4)}`; + if (digits.length >= 4) result += ')'; + if (digits.length > 4) result += ` ${digits.slice(4, 7)}`; + if (digits.length > 7) result += `-${digits.slice(7, 9)}`; + if (digits.length > 9) result += `-${digits.slice(9, 11)}`; + + return result; +}; + +export default function App(): ReactElement { + const [value, setValue] = useState(''); + const [promoCode, setPromoCode] = useState(''); + const [expiry, setExpiry] = useState(''); + const [phone, setPhone] = useState(''); + const [isFocused, setIsFocused] = useState(false); + const inputRef = useRef(null); + + const handleValueChange = (text: string): void => { + setValue(text.replace(/\d/g, '')); + }; + + const handleFocus = (): void => { + setIsFocused(true); + }; + + const handleBlur = (): void => { + setIsFocused(false); + }; + + const focus = (): void => { + inputRef.current?.focus(); + }; + + const blur = (): void => { + inputRef.current?.blur(); + }; + + const handlePhoneChange = (text: string): void => { + setPhone((prev) => { + const prevDigits = prev.replace(/\D/g, ''); + const nextDigits = text.replace(/\D/g, ''); + + if (text.length < prev.length && nextDigits === prevDigits && prevDigits.length > 0) { + return formatPhone(prevDigits.slice(0, -1)); + } + + return formatPhone(text); + }); + }; + + return ( + + { + console.log('onSubmitEditing'); + }} + /> + +