feat(smart-app): implement complete mobile app MVP

- App.tsx: full navigation (Auth stack + Main tabs with 5 screens)
- Auth: LoginScreen, RegisterScreen, ForgotPasswordScreen
- HomeScreen: dashboard with IoT metrics, weather widget, alerts, quick actions, sensors
- MapScreen: interactive map with layer toggles (6 layers)
- MarketplaceScreen: categories (6), products (5), search
- ChatScreen: AI chat with quick prompts (4), bot responses
- ProfileScreen: user info, stats, menu (9 items), logout
- AlertsScreen: alert list with severity, acknowledge
- SensorsScreen: sensor list with type filters (6 types), search
- ZonesScreen: zone cards with stats
- SettingsScreen: language picker (FR/EN/ES/DE), privacy, about
- Stores: iotStore (sensors, zones, alerts), notificationStore, uiStore + i18n
- Hooks: useSensors, useAlerts, useNotifications, useLocation
- Components: Card, Button, LoadingSpinner, ErrorBoundary, Header
- Services: iotService, notificationService (with axios API client)
- Utils: formatters (temp, AQI, noise, dates), validators (email, password, IBAN)
- Theme: colors.ts with full design system (Blue Ocean palette)
- Ditto: fixed MongoDB connection, new JWT secrets, official gateway image
This commit is contained in:
Eric FELIXINE
2026-06-01 18:00:35 -04:00
parent 08ca495bde
commit e30ae8ed09
35578 changed files with 3703534 additions and 43 deletions

View File

@@ -0,0 +1,766 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
*/
import type {
HostComponent,
PartialViewConfig,
} from '../../Renderer/shims/ReactNativeTypes';
import type {
ColorValue,
TextStyleProp,
ViewStyleProp,
} from '../../StyleSheet/StyleSheet';
import type {
BubblingEventHandler,
DirectEventHandler,
Double,
Float,
Int32,
WithDefault,
} from '../../Types/CodegenTypes';
import type {ViewProps} from '../View/ViewPropTypes';
import type {TextInputNativeCommands} from './TextInputNativeCommands';
import * as NativeComponentRegistry from '../../NativeComponent/NativeComponentRegistry';
import codegenNativeCommands from '../../Utilities/codegenNativeCommands';
export type KeyboardType =
// Cross Platform
| 'default'
| 'email-address'
| 'numeric'
| 'phone-pad'
| 'number-pad'
| 'decimal-pad'
| 'url'
// iOS-only
| 'ascii-capable'
| 'numbers-and-punctuation'
| 'name-phone-pad'
| 'twitter'
| 'web-search'
// Android-only
| 'visible-password';
export type ReturnKeyType =
// Cross Platform
| 'done'
| 'go'
| 'next'
| 'search'
| 'send'
// Android-only
| 'none'
| 'previous'
// iOS-only
| 'default'
| 'emergency-call'
| 'google'
| 'join'
| 'route'
| 'yahoo';
export type SubmitBehavior = 'submit' | 'blurAndSubmit' | 'newline';
export type NativeProps = $ReadOnly<{|
// This allows us to inherit everything from ViewProps except for style (see below)
// This must be commented for Fabric codegen to work.
...$Diff<ViewProps, $ReadOnly<{|style: ?ViewStyleProp|}>>,
/**
* Android props after this
*/
/**
* Specifies autocomplete hints for the system, so it can provide autofill. On Android, the system will always attempt to offer autofill by using heuristics to identify the type of content.
* To disable autocomplete, set `autoComplete` to `off`.
*
* *Android Only*
*
* Possible values for `autoComplete` are:
*
* - `birthdate-day`
* - `birthdate-full`
* - `birthdate-month`
* - `birthdate-year`
* - `cc-csc`
* - `cc-exp`
* - `cc-exp-day`
* - `cc-exp-month`
* - `cc-exp-year`
* - `cc-number`
* - `email`
* - `gender`
* - `name`
* - `name-family`
* - `name-given`
* - `name-middle`
* - `name-middle-initial`
* - `name-prefix`
* - `name-suffix`
* - `password`
* - `password-new`
* - `postal-address`
* - `postal-address-country`
* - `postal-address-extended`
* - `postal-address-extended-postal-code`
* - `postal-address-locality`
* - `postal-address-region`
* - `postal-code`
* - `street-address`
* - `sms-otp`
* - `tel`
* - `tel-country-code`
* - `tel-national`
* - `tel-device`
* - `username`
* - `username-new`
* - `off`
*
* @platform android
*/
autoComplete?: WithDefault<
| 'birthdate-day'
| 'birthdate-full'
| 'birthdate-month'
| 'birthdate-year'
| 'cc-csc'
| 'cc-exp'
| 'cc-exp-day'
| 'cc-exp-month'
| 'cc-exp-year'
| 'cc-number'
| 'email'
| 'gender'
| 'name'
| 'name-family'
| 'name-given'
| 'name-middle'
| 'name-middle-initial'
| 'name-prefix'
| 'name-suffix'
| 'password'
| 'password-new'
| 'postal-address'
| 'postal-address-country'
| 'postal-address-extended'
| 'postal-address-extended-postal-code'
| 'postal-address-locality'
| 'postal-address-region'
| 'postal-code'
| 'street-address'
| 'sms-otp'
| 'tel'
| 'tel-country-code'
| 'tel-national'
| 'tel-device'
| 'username'
| 'username-new'
| 'off',
'off',
>,
/**
* Sets the return key to the label. Use it instead of `returnKeyType`.
* @platform android
*/
returnKeyLabel?: ?string,
/**
* Sets the number of lines for a `TextInput`. Use it with multiline set to
* `true` to be able to fill the lines.
* @platform android
*/
numberOfLines?: ?Int32,
/**
* When `false`, if there is a small amount of space available around a text input
* (e.g. landscape orientation on a phone), the OS may choose to have the user edit
* the text inside of a full screen text input mode. When `true`, this feature is
* disabled and users will always edit the text directly inside of the text input.
* Defaults to `false`.
* @platform android
*/
disableFullscreenUI?: ?boolean,
/**
* Set text break strategy on Android API Level 23+, possible values are `simple`, `highQuality`, `balanced`
* The default value is `simple`.
* @platform android
*/
textBreakStrategy?: WithDefault<
'simple' | 'highQuality' | 'balanced',
'simple',
>,
/**
* The color of the `TextInput` underline.
* @platform android
*/
underlineColorAndroid?: ?ColorValue,
/**
* If defined, the provided image resource will be rendered on the left.
* The image resource must be inside `/android/app/src/main/res/drawable` and referenced
* like
* ```
* <TextInput
* inlineImageLeft='search_icon'
* />
* ```
* @platform android
*/
inlineImageLeft?: ?string,
/**
* Padding between the inline image, if any, and the text input itself.
* @platform android
*/
inlineImagePadding?: ?Int32,
importantForAutofill?: string /*?(
| 'auto'
| 'no'
| 'noExcludeDescendants'
| 'yes'
| 'yesExcludeDescendants'
),*/,
/**
* When `false`, it will prevent the soft keyboard from showing when the field is focused.
* Defaults to `true`.
*/
showSoftInputOnFocus?: ?boolean,
/**
* TextInput props after this
*/
/**
* Can tell `TextInput` to automatically capitalize certain characters.
*
* - `characters`: all characters.
* - `words`: first letter of each word.
* - `sentences`: first letter of each sentence (*default*).
* - `none`: don't auto capitalize anything.
*/
autoCapitalize?: WithDefault<
'none' | 'sentences' | 'words' | 'characters',
'none',
>,
/**
* If `false`, disables auto-correct. The default value is `true`.
*/
autoCorrect?: ?boolean,
/**
* If `true`, focuses the input on `componentDidMount`.
* The default value is `false`.
*/
autoFocus?: ?boolean,
/**
* Specifies whether fonts should scale to respect Text Size accessibility settings. The
* default is `true`.
*/
allowFontScaling?: ?boolean,
/**
* Specifies largest possible scale a font can reach when `allowFontScaling` is enabled.
* Possible values:
* `null/undefined` (default): inherit from the parent node or the global default (0)
* `0`: no max, ignore parent/global default
* `>= 1`: sets the maxFontSizeMultiplier of this node to this value
*/
maxFontSizeMultiplier?: ?Float,
/**
* If `false`, text is not editable. The default value is `true`.
*/
editable?: ?boolean,
/**
* Determines which keyboard to open, e.g.`numeric`.
*
* The following values work across platforms:
*
* - `default`
* - `numeric`
* - `number-pad`
* - `decimal-pad`
* - `email-address`
* - `phone-pad`
* - `url`
*
* *Android Only*
*
* The following values work on Android only:
*
* - `visible-password`
*/
keyboardType?: WithDefault<KeyboardType, 'default'>,
/**
* Determines how the return key should look. On Android you can also use
* `returnKeyLabel`.
*
* *Cross platform*
*
* The following values work across platforms:
*
* - `done`
* - `go`
* - `next`
* - `search`
* - `send`
*
* *Android Only*
*
* The following values work on Android only:
*
* - `none`
* - `previous`
*/
returnKeyType?: WithDefault<ReturnKeyType, 'done'>,
/**
* Limits the maximum number of characters that can be entered. Use this
* instead of implementing the logic in JS to avoid flicker.
*/
maxLength?: ?Int32,
/**
* If `true`, the text input can be multiple lines.
* The default value is `false`.
*/
multiline?: ?boolean,
/**
* Callback that is called when the text input is blurred.
* `target` is the reactTag of the element
*/
onBlur?: ?BubblingEventHandler<$ReadOnly<{|target: Int32|}>>,
/**
* Callback that is called when the text input is focused.
* `target` is the reactTag of the element
*/
onFocus?: ?BubblingEventHandler<$ReadOnly<{|target: Int32|}>>,
/**
* Callback that is called when the text input's text changes.
* `target` is the reactTag of the element
* TODO: differentiate between onChange and onChangeText
*/
onChange?: ?BubblingEventHandler<
$ReadOnly<{|target: Int32, eventCount: Int32, text: string|}>,
>,
/**
* Callback that is called when the text input's text changes.
* Changed text is passed as an argument to the callback handler.
* TODO: differentiate between onChange and onChangeText
*/
onChangeText?: ?BubblingEventHandler<
$ReadOnly<{|target: Int32, eventCount: Int32, text: string|}>,
>,
/**
* Callback that is called when the text input's content size changes.
* This will be called with
* `{ nativeEvent: { contentSize: { width, height } } }`.
*
* Only called for multiline text inputs.
*/
onContentSizeChange?: ?DirectEventHandler<
$ReadOnly<{|
target: Int32,
contentSize: $ReadOnly<{|width: Double, height: Double|}>,
|}>,
>,
onTextInput?: ?BubblingEventHandler<
$ReadOnly<{|
target: Int32,
text: string,
previousText: string,
range: $ReadOnly<{|start: Double, end: Double|}>,
|}>,
>,
/**
* Callback that is called when text input ends.
*/
onEndEditing?: ?BubblingEventHandler<
$ReadOnly<{|target: Int32, text: string|}>,
>,
/**
* Callback that is called when the text input selection is changed.
* This will be called with
* `{ nativeEvent: { selection: { start, end } } }`.
*/
onSelectionChange?: ?DirectEventHandler<
$ReadOnly<{|
target: Int32,
selection: $ReadOnly<{|start: Double, end: Double|}>,
|}>,
>,
/**
* Callback that is called when the text input's submit button is pressed.
* Invalid if `multiline={true}` is specified.
*/
onSubmitEditing?: ?BubblingEventHandler<
$ReadOnly<{|target: Int32, text: string|}>,
>,
/**
* Callback that is called when a key is pressed.
* This will be called with `{ nativeEvent: { key: keyValue } }`
* where `keyValue` is `'Enter'` or `'Backspace'` for respective keys and
* the typed-in character otherwise including `' '` for space.
* Fires before `onChange` callbacks.
*/
onKeyPress?: ?BubblingEventHandler<$ReadOnly<{|target: Int32, key: string|}>>,
/**
* Invoked on content scroll with `{ nativeEvent: { contentOffset: { x, y } } }`.
* May also contain other properties from ScrollEvent but on Android contentSize
* is not provided for performance reasons.
*/
onScroll?: ?DirectEventHandler<
$ReadOnly<{|
target: Int32,
responderIgnoreScroll: boolean,
contentInset: $ReadOnly<{|
top: Double, // always 0 on Android
bottom: Double, // always 0 on Android
left: Double, // always 0 on Android
right: Double, // always 0 on Android
|}>,
contentOffset: $ReadOnly<{|
x: Double,
y: Double,
|}>,
contentSize: $ReadOnly<{|
width: Double, // always 0 on Android
height: Double, // always 0 on Android
|}>,
layoutMeasurement: $ReadOnly<{|
width: Double,
height: Double,
|}>,
velocity: $ReadOnly<{|
x: Double, // always 0 on Android
y: Double, // always 0 on Android
|}>,
|}>,
>,
/**
* The string that will be rendered before text input has been entered.
*/
placeholder?: ?Stringish,
/**
* The text color of the placeholder string.
*/
placeholderTextColor?: ?ColorValue,
/**
* If `true`, the text input obscures the text entered so that sensitive text
* like passwords stay secure. The default value is `false`. Does not work with 'multiline={true}'.
*/
secureTextEntry?: ?boolean,
/**
* The highlight and cursor color of the text input.
*/
selectionColor?: ?ColorValue,
/**
* The text selection handle color.
*/
selectionHandleColor?: ?ColorValue,
/**
* The start and end of the text input's selection. Set start and end to
* the same value to position the cursor.
*/
selection?: ?$ReadOnly<{|
start: Int32,
end?: ?Int32,
|}>,
/**
* The value to show for the text input. `TextInput` is a controlled
* component, which means the native value will be forced to match this
* value prop if provided. For most uses, this works great, but in some
* cases this may cause flickering - one common cause is preventing edits
* by keeping value the same. In addition to simply setting the same value,
* either set `editable={false}`, or set/update `maxLength` to prevent
* unwanted edits without flicker.
*/
value?: ?string,
/**
* Provides an initial value that will change when the user starts typing.
* Useful for simple use-cases where you do not want to deal with listening
* to events and updating the value prop to keep the controlled state in sync.
*/
defaultValue?: ?string,
/**
* If `true`, all text will automatically be selected on focus.
*/
selectTextOnFocus?: ?boolean,
/**
* If `true`, the text field will blur when submitted.
* The default value is true for single-line fields and false for
* multiline fields. Note that for multiline fields, setting `blurOnSubmit`
* to `true` means that pressing return will blur the field and trigger the
* `onSubmitEditing` event instead of inserting a newline into the field.
*
* @deprecated
* Note that `submitBehavior` now takes the place of `blurOnSubmit` and will
* override any behavior defined by `blurOnSubmit`.
* @see submitBehavior
*/
blurOnSubmit?: ?boolean,
/**
* When the return key is pressed,
*
* For single line inputs:
*
* - `'newline`' defaults to `'blurAndSubmit'`
* - `undefined` defaults to `'blurAndSubmit'`
*
* For multiline inputs:
*
* - `'newline'` adds a newline
* - `undefined` defaults to `'newline'`
*
* For both single line and multiline inputs:
*
* - `'submit'` will only send a submit event and not blur the input
* - `'blurAndSubmit`' will both blur the input and send a submit event
*/
submitBehavior?: ?SubmitBehavior,
/**
* Note that not all Text styles are supported, an incomplete list of what is not supported includes:
*
* - `borderLeftWidth`
* - `borderTopWidth`
* - `borderRightWidth`
* - `borderBottomWidth`
* - `borderTopLeftRadius`
* - `borderTopRightRadius`
* - `borderBottomRightRadius`
* - `borderBottomLeftRadius`
*
* see [Issue#7070](https://github.com/facebook/react-native/issues/7070)
* for more detail.
*
* [Styles](docs/style.html)
*/
// TODO: figure out what to do with this style prop for codegen/Fabric purposes
// This must be commented for Fabric codegen to work; it's currently not possible
// to override the default View style prop in codegen.
style?: ?TextStyleProp,
/**
* If `true`, caret is hidden. The default value is `false`.
* This property is supported only for single-line TextInput component on iOS.
*/
caretHidden?: ?boolean,
/*
* If `true`, contextMenuHidden is hidden. The default value is `false`.
*/
contextMenuHidden?: ?boolean,
/**
* The following are props that `BaseTextShadowNode` takes. It is unclear if they
* are used by TextInput.
*/
textShadowColor?: ?ColorValue,
textShadowRadius?: ?Float,
textDecorationLine?: ?string,
fontStyle?: ?string,
textShadowOffset?: ?$ReadOnly<{|width?: ?Double, height?: ?Double|}>,
lineHeight?: ?Float,
textTransform?: ?string,
color?: ?Int32,
letterSpacing?: ?Float,
fontSize?: ?Float,
textAlign?: ?string,
includeFontPadding?: ?boolean,
fontWeight?: ?string,
fontFamily?: ?string,
/**
* I cannot find where these are defined but JS complains without them.
*/
textAlignVertical?: ?string,
cursorColor?: ?ColorValue,
/**
* "Private" fields used by TextInput.js and not users of this component directly
*/
mostRecentEventCount: Int32,
text?: ?string,
|}>;
type NativeType = HostComponent<NativeProps>;
type NativeCommands = TextInputNativeCommands<NativeType>;
export const Commands: NativeCommands = codegenNativeCommands<NativeCommands>({
supportedCommands: ['focus', 'blur', 'setTextAndSelection'],
});
export const __INTERNAL_VIEW_CONFIG: PartialViewConfig = {
uiViewClassName: 'AndroidTextInput',
bubblingEventTypes: {
topBlur: {
phasedRegistrationNames: {
bubbled: 'onBlur',
captured: 'onBlurCapture',
},
},
topEndEditing: {
phasedRegistrationNames: {
bubbled: 'onEndEditing',
captured: 'onEndEditingCapture',
},
},
topFocus: {
phasedRegistrationNames: {
bubbled: 'onFocus',
captured: 'onFocusCapture',
},
},
topKeyPress: {
phasedRegistrationNames: {
bubbled: 'onKeyPress',
captured: 'onKeyPressCapture',
},
},
topSubmitEditing: {
phasedRegistrationNames: {
bubbled: 'onSubmitEditing',
captured: 'onSubmitEditingCapture',
},
},
topTextInput: {
phasedRegistrationNames: {
bubbled: 'onTextInput',
captured: 'onTextInputCapture',
},
},
},
directEventTypes: {
topScroll: {
registrationName: 'onScroll',
},
},
validAttributes: {
maxFontSizeMultiplier: true,
adjustsFontSizeToFit: true,
minimumFontScale: true,
autoFocus: true,
placeholder: true,
inlineImagePadding: true,
contextMenuHidden: true,
textShadowColor: {
process: require('../../StyleSheet/processColor').default,
},
maxLength: true,
selectTextOnFocus: true,
textShadowRadius: true,
underlineColorAndroid: {
process: require('../../StyleSheet/processColor').default,
},
textDecorationLine: true,
submitBehavior: true,
textAlignVertical: true,
fontStyle: true,
textShadowOffset: true,
selectionColor: {process: require('../../StyleSheet/processColor').default},
selectionHandleColor: {
process: require('../../StyleSheet/processColor').default,
},
placeholderTextColor: {
process: require('../../StyleSheet/processColor').default,
},
importantForAutofill: true,
lineHeight: true,
textTransform: true,
returnKeyType: true,
keyboardType: true,
multiline: true,
color: {process: require('../../StyleSheet/processColor').default},
autoComplete: true,
numberOfLines: true,
letterSpacing: true,
returnKeyLabel: true,
fontSize: true,
onKeyPress: true,
cursorColor: {process: require('../../StyleSheet/processColor').default},
text: true,
showSoftInputOnFocus: true,
textAlign: true,
autoCapitalize: true,
autoCorrect: true,
caretHidden: true,
secureTextEntry: true,
textBreakStrategy: true,
onScroll: true,
onContentSizeChange: true,
disableFullscreenUI: true,
includeFontPadding: true,
fontWeight: true,
fontFamily: true,
allowFontScaling: true,
onSelectionChange: true,
mostRecentEventCount: true,
inlineImageLeft: true,
editable: true,
fontVariant: true,
borderBottomRightRadius: true,
borderBottomColor: {
process: require('../../StyleSheet/processColor').default,
},
borderRadius: true,
borderRightColor: {
process: require('../../StyleSheet/processColor').default,
},
borderColor: {process: require('../../StyleSheet/processColor').default},
borderTopRightRadius: true,
borderStyle: true,
borderBottomLeftRadius: true,
borderLeftColor: {
process: require('../../StyleSheet/processColor').default,
},
borderTopLeftRadius: true,
borderTopColor: {process: require('../../StyleSheet/processColor').default},
},
};
let AndroidTextInputNativeComponent = NativeComponentRegistry.get<NativeProps>(
'AndroidTextInput',
() => __INTERNAL_VIEW_CONFIG,
);
// flowlint-next-line unclear-type:off
export default ((AndroidTextInputNativeComponent: any): HostComponent<NativeProps>);

View File

@@ -0,0 +1,34 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/
import type * as React from 'react';
import {ColorValue, StyleProp} from '../../StyleSheet/StyleSheet';
import {ViewStyle} from '../../StyleSheet/StyleSheetTypes';
/**
* A component which enables customization of the keyboard input accessory view on iOS. The input accessory view is
* displayed above the keyboard whenever a TextInput has focus. This component can be used to create custom toolbars.
*
* To use this component wrap your custom toolbar with the InputAccessoryView component, and set a nativeID. Then, pass
* that nativeID as the inputAccessoryViewID of whatever TextInput you desire.
*/
export class InputAccessoryView extends React.Component<InputAccessoryViewProps> {}
export interface InputAccessoryViewProps {
backgroundColor?: ColorValue | undefined;
children?: React.ReactNode | undefined;
/**
* An ID which is used to associate this InputAccessoryView to specified TextInput(s).
*/
nativeID?: string | undefined;
style?: StyleProp<ViewStyle> | undefined;
}

View File

@@ -0,0 +1,114 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
*/
import StyleSheet, {
type ColorValue,
type ViewStyleProp,
} from '../../StyleSheet/StyleSheet';
import Platform from '../../Utilities/Platform';
import RCTInputAccessoryViewNativeComponent from './RCTInputAccessoryViewNativeComponent';
import * as React from 'react';
/**
* Note: iOS only
*
* A component which enables customization of the keyboard input accessory view.
* The input accessory view is displayed above the keyboard whenever a TextInput
* has focus. This component can be used to create custom toolbars.
*
* To use this component wrap your custom toolbar with the
* InputAccessoryView component, and set a nativeID. Then, pass that nativeID
* as the inputAccessoryViewID of whatever TextInput you desire. A simple
* example:
*
* ```ReactNativeWebPlayer
* import React, { Component } from 'react';
* import { AppRegistry, TextInput, InputAccessoryView, Button } from 'react-native';
*
* export default class UselessTextInput extends Component {
* constructor(props) {
* super(props);
* this.state = {text: 'Placeholder Text'};
* }
*
* render() {
* const inputAccessoryViewID = "uniqueID";
* return (
* <View>
* <ScrollView keyboardDismissMode="interactive">
* <TextInput
* style={{
* padding: 10,
* paddingTop: 50,
* }}
* inputAccessoryViewID=inputAccessoryViewID
* onChangeText={text => this.setState({text})}
* value={this.state.text}
* />
* </ScrollView>
* <InputAccessoryView nativeID=inputAccessoryViewID>
* <Button
* onPress={() => this.setState({text: 'Placeholder Text'})}
* title="Reset Text"
* />
* </InputAccessoryView>
* </View>
* );
* }
* }
*
* // skip this line if using Create React Native App
* AppRegistry.registerComponent('AwesomeProject', () => UselessTextInput);
* ```
*
* This component can also be used to create sticky text inputs (text inputs
* which are anchored to the top of the keyboard). To do this, wrap a
* TextInput with the InputAccessoryView component, and don't set a nativeID.
* For an example, look at InputAccessoryViewExample.js in RNTester.
*/
type Props = $ReadOnly<{|
+children: React.Node,
/**
* An ID which is used to associate this `InputAccessoryView` to
* specified TextInput(s).
*/
nativeID?: ?string,
style?: ?ViewStyleProp,
backgroundColor?: ?ColorValue,
|}>;
const InputAccessoryView: React.AbstractComponent<Props> = (props: Props) => {
if (Platform.OS === 'ios') {
if (React.Children.count(props.children) === 0) {
return null;
}
return (
<RCTInputAccessoryViewNativeComponent
style={[props.style, styles.container]}
nativeID={props.nativeID}
backgroundColor={props.backgroundColor}>
{props.children}
</RCTInputAccessoryViewNativeComponent>
);
} else {
console.warn('<InputAccessoryView> is only supported on iOS.');
return null;
}
};
const styles = StyleSheet.create({
container: {
position: 'absolute',
},
});
export default InputAccessoryView;

View File

@@ -0,0 +1,13 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @flow strict-local
*/
export * from '../../../src/private/specs/components/RCTInputAccessoryViewNativeComponent';
import RCTInputAccessoryViewNativeComponent from '../../../src/private/specs/components/RCTInputAccessoryViewNativeComponent';
export default RCTInputAccessoryViewNativeComponent;

View File

@@ -0,0 +1,45 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
*/
import type {
HostComponent,
PartialViewConfig,
} from '../../Renderer/shims/ReactNativeTypes';
import type {TextInputNativeCommands} from './TextInputNativeCommands';
import * as NativeComponentRegistry from '../../NativeComponent/NativeComponentRegistry';
import codegenNativeCommands from '../../Utilities/codegenNativeCommands';
import RCTTextInputViewConfig from './RCTTextInputViewConfig';
type NativeType = HostComponent<mixed>;
type NativeCommands = TextInputNativeCommands<NativeType>;
export const Commands: NativeCommands = codegenNativeCommands<NativeCommands>({
supportedCommands: ['focus', 'blur', 'setTextAndSelection'],
});
export const __INTERNAL_VIEW_CONFIG: PartialViewConfig = {
uiViewClassName: 'RCTMultilineTextInputView',
...RCTTextInputViewConfig,
validAttributes: {
...RCTTextInputViewConfig.validAttributes,
dataDetectorTypes: true,
},
};
const MultilineTextInputNativeComponent: HostComponent<mixed> =
NativeComponentRegistry.get<mixed>(
'RCTMultilineTextInputView',
() => __INTERNAL_VIEW_CONFIG,
);
// flowlint-next-line unclear-type:off
export default ((MultilineTextInputNativeComponent: any): HostComponent<mixed>);

View File

@@ -0,0 +1,41 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
*/
import type {
HostComponent,
PartialViewConfig,
} from '../../Renderer/shims/ReactNativeTypes';
import type {TextInputNativeCommands} from './TextInputNativeCommands';
import * as NativeComponentRegistry from '../../NativeComponent/NativeComponentRegistry';
import codegenNativeCommands from '../../Utilities/codegenNativeCommands';
import RCTTextInputViewConfig from './RCTTextInputViewConfig';
type NativeType = HostComponent<mixed>;
type NativeCommands = TextInputNativeCommands<NativeType>;
export const Commands: NativeCommands = codegenNativeCommands<NativeCommands>({
supportedCommands: ['focus', 'blur', 'setTextAndSelection'],
});
export const __INTERNAL_VIEW_CONFIG: PartialViewConfig = {
uiViewClassName: 'RCTSinglelineTextInputView',
...RCTTextInputViewConfig,
};
const SinglelineTextInputNativeComponent: HostComponent<mixed> =
NativeComponentRegistry.get<mixed>(
'RCTSinglelineTextInputView',
() => __INTERNAL_VIEW_CONFIG,
);
// flowlint-next-line unclear-type:off
export default ((SinglelineTextInputNativeComponent: any): HostComponent<mixed>);

View File

@@ -0,0 +1,169 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
*/
import type {PartialViewConfig} from '../../Renderer/shims/ReactNativeTypes';
import {ConditionallyIgnoredEventHandlers} from '../../NativeComponent/ViewConfigIgnore';
type PartialViewConfigWithoutName = $Rest<
PartialViewConfig,
{uiViewClassName: string},
>;
const RCTTextInputViewConfig = {
bubblingEventTypes: {
topBlur: {
phasedRegistrationNames: {
bubbled: 'onBlur',
captured: 'onBlurCapture',
},
},
topChange: {
phasedRegistrationNames: {
bubbled: 'onChange',
captured: 'onChangeCapture',
},
},
topEndEditing: {
phasedRegistrationNames: {
bubbled: 'onEndEditing',
captured: 'onEndEditingCapture',
},
},
topFocus: {
phasedRegistrationNames: {
bubbled: 'onFocus',
captured: 'onFocusCapture',
},
},
topKeyPress: {
phasedRegistrationNames: {
bubbled: 'onKeyPress',
captured: 'onKeyPressCapture',
},
},
topSubmitEditing: {
phasedRegistrationNames: {
bubbled: 'onSubmitEditing',
captured: 'onSubmitEditingCapture',
},
},
topTouchCancel: {
phasedRegistrationNames: {
bubbled: 'onTouchCancel',
captured: 'onTouchCancelCapture',
},
},
topTouchEnd: {
phasedRegistrationNames: {
bubbled: 'onTouchEnd',
captured: 'onTouchEndCapture',
},
},
topTouchMove: {
phasedRegistrationNames: {
bubbled: 'onTouchMove',
captured: 'onTouchMoveCapture',
},
},
},
directEventTypes: {
topTextInput: {
registrationName: 'onTextInput',
},
topKeyPressSync: {
registrationName: 'onKeyPressSync',
},
topScroll: {
registrationName: 'onScroll',
},
topSelectionChange: {
registrationName: 'onSelectionChange',
},
topChangeSync: {
registrationName: 'onChangeSync',
},
topContentSizeChange: {
registrationName: 'onContentSizeChange',
},
},
validAttributes: {
fontSize: true,
fontWeight: true,
fontVariant: true,
// flowlint-next-line untyped-import:off
textShadowOffset: {diff: require('../../Utilities/differ/sizesDiffer')},
allowFontScaling: true,
fontStyle: true,
textTransform: true,
textAlign: true,
fontFamily: true,
lineHeight: true,
isHighlighted: true,
writingDirection: true,
textDecorationLine: true,
textShadowRadius: true,
letterSpacing: true,
textDecorationStyle: true,
textDecorationColor: {
process: require('../../StyleSheet/processColor').default,
},
color: {process: require('../../StyleSheet/processColor').default},
maxFontSizeMultiplier: true,
textShadowColor: {
process: require('../../StyleSheet/processColor').default,
},
editable: true,
inputAccessoryViewID: true,
caretHidden: true,
enablesReturnKeyAutomatically: true,
placeholderTextColor: {
process: require('../../StyleSheet/processColor').default,
},
clearButtonMode: true,
keyboardType: true,
selection: true,
returnKeyType: true,
submitBehavior: true,
mostRecentEventCount: true,
scrollEnabled: true,
selectionColor: {process: require('../../StyleSheet/processColor').default},
contextMenuHidden: true,
secureTextEntry: true,
placeholder: true,
autoCorrect: true,
multiline: true,
textContentType: true,
maxLength: true,
autoCapitalize: true,
keyboardAppearance: true,
passwordRules: true,
spellCheck: true,
selectTextOnFocus: true,
text: true,
clearTextOnFocus: true,
showSoftInputOnFocus: true,
autoFocus: true,
lineBreakStrategyIOS: true,
smartInsertDelete: true,
...ConditionallyIgnoredEventHandlers({
onChange: true,
onSelectionChange: true,
onContentSizeChange: true,
onScroll: true,
onChangeSync: true,
onKeyPressSync: true,
onTextInput: true,
}),
},
};
module.exports = (RCTTextInputViewConfig: PartialViewConfigWithoutName);

View File

@@ -0,0 +1,973 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/
import type * as React from 'react';
import {Constructor} from '../../../types/private/Utilities';
import {TimerMixin} from '../../../types/private/TimerMixin';
import {
HostComponent,
NativeMethods,
} from '../../../types/public/ReactNativeTypes';
import {ColorValue, StyleProp} from '../../StyleSheet/StyleSheet';
import {TextStyle} from '../../StyleSheet/StyleSheetTypes';
import {
NativeSyntheticEvent,
NativeTouchEvent,
TargetedEvent,
} from '../../Types/CoreEventTypes';
import EventEmitter from '../../vendor/emitter/EventEmitter';
import {AccessibilityProps} from '../View/ViewAccessibility';
import {ViewProps} from '../View/ViewPropTypes';
export type KeyboardType =
| 'default'
| 'number-pad'
| 'decimal-pad'
| 'numeric'
| 'email-address'
| 'phone-pad'
| 'url';
export type KeyboardTypeIOS =
| 'ascii-capable'
| 'numbers-and-punctuation'
| 'name-phone-pad'
| 'twitter'
| 'web-search';
export type KeyboardTypeAndroid = 'visible-password';
export type KeyboardTypeOptions =
| KeyboardType
| KeyboardTypeAndroid
| KeyboardTypeIOS;
export type InputModeOptions =
| 'none'
| 'text'
| 'decimal'
| 'numeric'
| 'tel'
| 'search'
| 'email'
| 'url';
export type ReturnKeyType = 'done' | 'go' | 'next' | 'search' | 'send';
export type ReturnKeyTypeAndroid = 'none' | 'previous';
export type ReturnKeyTypeIOS =
| 'default'
| 'google'
| 'join'
| 'route'
| 'yahoo'
| 'emergency-call';
export type ReturnKeyTypeOptions =
| ReturnKeyType
| ReturnKeyTypeAndroid
| ReturnKeyTypeIOS;
export type EnterKeyHintTypeAndroid = 'previous';
export type EnterKeyHintTypeIOS = 'enter';
export type EnterKeyHintType = 'done' | 'go' | 'next' | 'search' | 'send';
export type EnterKeyHintTypeOptions =
| EnterKeyHintType
| EnterKeyHintTypeAndroid
| EnterKeyHintTypeIOS;
type DataDetectorTypes =
| 'phoneNumber'
| 'link'
| 'address'
| 'calendarEvent'
| 'trackingNumber'
| 'flightNumber'
| 'lookupSuggestion'
| 'none'
| 'all';
/**
* DocumentSelectionState is responsible for maintaining selection information
* for a document.
*
* It is intended for use by AbstractTextEditor-based components for
* identifying the appropriate start/end positions to modify the
* DocumentContent, and for programmatically setting browser selection when
* components re-render.
*/
export interface DocumentSelectionState extends EventEmitter {
new (anchor: number, focus: number): DocumentSelectionState;
/**
* Apply an update to the state. If either offset value has changed,
* set the values and emit the `change` event. Otherwise no-op.
*
*/
update(anchor: number, focus: number): void;
/**
* Given a max text length, constrain our selection offsets to ensure
* that the selection remains strictly within the text range.
*
*/
constrainLength(maxLength: number): void;
focus(): void;
blur(): void;
hasFocus(): boolean;
isCollapsed(): boolean;
isBackward(): boolean;
getAnchorOffset(): number;
getFocusOffset(): number;
getStartOffset(): number;
getEndOffset(): number;
overlaps(start: number, end: number): boolean;
}
/**
* IOS Specific properties for TextInput
* @see https://reactnative.dev/docs/textinput#props
*/
export interface TextInputIOSProps {
/**
* enum('never', 'while-editing', 'unless-editing', 'always')
* When the clear button should appear on the right side of the text view
*/
clearButtonMode?:
| 'never'
| 'while-editing'
| 'unless-editing'
| 'always'
| undefined;
/**
* If true, clears the text field automatically when editing begins
*/
clearTextOnFocus?: boolean | undefined;
/**
* Determines the types of data converted to clickable URLs in the text input.
* Only valid if `multiline={true}` and `editable={false}`.
* By default no data types are detected.
*
* You can provide one type or an array of many types.
*
* Possible values for `dataDetectorTypes` are:
*
* - `'phoneNumber'`
* - `'link'`
* - `'address'`
* - `'calendarEvent'`
* - `'none'`
* - `'all'`
*/
dataDetectorTypes?: DataDetectorTypes | DataDetectorTypes[] | undefined;
/**
* If true, the keyboard disables the return key when there is no text and automatically enables it when there is text.
* The default value is false.
*/
enablesReturnKeyAutomatically?: boolean | undefined;
/**
* Determines the color of the keyboard.
*/
keyboardAppearance?: 'default' | 'light' | 'dark' | undefined;
/**
* Provide rules for your password.
* For example, say you want to require a password with at least eight characters consisting of a mix of uppercase and lowercase letters, at least one number, and at most two consecutive characters.
* "required: upper; required: lower; required: digit; max-consecutive: 2; minlength: 8;"
*/
passwordRules?: string | null | undefined;
/**
* If `true`, allows TextInput to pass touch events to the parent component.
* This allows components to be swipeable from the TextInput on iOS,
* as is the case on Android by default.
* If `false`, TextInput always asks to handle the input (except when disabled).
*/
rejectResponderTermination?: boolean | null | undefined;
/**
* See DocumentSelectionState.js, some state that is responsible for maintaining selection information for a document
*/
selectionState?: DocumentSelectionState | undefined;
/**
* If false, disables spell-check style (i.e. red underlines). The default value is inherited from autoCorrect
*/
spellCheck?: boolean | undefined;
/**
* Give the keyboard and the system information about the expected
* semantic meaning for the content that users enter.
*
* To disable autofill, set textContentType to `none`.
*
* Possible values for `textContentType` are:
*
* - `'none'`
* - `'URL'`
* - `'addressCity'`
* - `'addressCityAndState'`
* - `'addressState'`
* - `'countryName'`
* - `'creditCardNumber'`
* - `'creditCardExpiration'` (iOS 17+)
* - `'creditCardExpirationMonth'` (iOS 17+)
* - `'creditCardExpirationYear'` (iOS 17+)
* - `'creditCardSecurityCode'` (iOS 17+)
* - `'creditCardType'` (iOS 17+)
* - `'creditCardName'` (iOS 17+)
* - `'creditCardGivenName'` (iOS 17+)
* - `'creditCardMiddleName'` (iOS 17+)
* - `'creditCardFamilyName'` (iOS 17+)
* - `'emailAddress'`
* - `'familyName'`
* - `'fullStreetAddress'`
* - `'givenName'`
* - `'jobTitle'`
* - `'location'`
* - `'middleName'`
* - `'name'`
* - `'namePrefix'`
* - `'nameSuffix'`
* - `'nickname'`
* - `'organizationName'`
* - `'postalCode'`
* - `'streetAddressLine1'`
* - `'streetAddressLine2'`
* - `'sublocality'`
* - `'telephoneNumber'`
* - `'username'`
* - `'password'`
* - `'newPassword'`
* - `'oneTimeCode'`
* - `'birthdate'` (iOS 17+)
* - `'birthdateDay'` (iOS 17+)
* - `'birthdateMonth'` (iOS 17+)
* - `'birthdateYear'` (iOS 17+)
*
*/
textContentType?:
| 'none'
| 'URL'
| 'addressCity'
| 'addressCityAndState'
| 'addressState'
| 'countryName'
| 'creditCardNumber'
| 'creditCardExpiration'
| 'creditCardExpirationMonth'
| 'creditCardExpirationYear'
| 'creditCardSecurityCode'
| 'creditCardType'
| 'creditCardName'
| 'creditCardGivenName'
| 'creditCardMiddleName'
| 'creditCardFamilyName'
| 'emailAddress'
| 'familyName'
| 'fullStreetAddress'
| 'givenName'
| 'jobTitle'
| 'location'
| 'middleName'
| 'name'
| 'namePrefix'
| 'nameSuffix'
| 'nickname'
| 'organizationName'
| 'postalCode'
| 'streetAddressLine1'
| 'streetAddressLine2'
| 'sublocality'
| 'telephoneNumber'
| 'username'
| 'password'
| 'newPassword'
| 'oneTimeCode'
| 'birthdate'
| 'birthdateDay'
| 'birthdateMonth'
| 'birthdateYear'
| undefined;
/**
* If false, scrolling of the text view will be disabled. The default value is true. Only works with multiline={true}
*/
scrollEnabled?: boolean | undefined;
/**
* Set line break strategy on iOS.
*/
lineBreakStrategyIOS?:
| 'none'
| 'standard'
| 'hangul-word'
| 'push-out'
| undefined;
/**
* If `false`, the iOS system will not insert an extra space after a paste operation
* neither delete one or two spaces after a cut or delete operation.
*
* The default value is `true`.
*/
smartInsertDelete?: boolean | undefined;
}
/**
* Android Specific properties for TextInput
* @see https://reactnative.dev/docs/textinput#props
*/
export interface TextInputAndroidProps {
/**
* When provided it will set the color of the cursor (or "caret") in the component.
* Unlike the behavior of `selectionColor` the cursor color will be set independently
* from the color of the text selection box.
* @platform android
*/
cursorColor?: ColorValue | null | undefined;
/**
* When provided it will set the color of the selection handles when highlighting text.
* Unlike the behavior of `selectionColor` the handle color will be set independently
* from the color of the text selection box.
* @platform android
*/
selectionHandleColor?: ColorValue | null | undefined;
/**
* Determines whether the individual fields in your app should be included in a
* view structure for autofill purposes on Android API Level 26+. Defaults to auto.
* To disable auto complete, use `off`.
*
* *Android Only*
*
* The following values work on Android only:
*
* - `auto` - let Android decide
* - `no` - not important for autofill
* - `noExcludeDescendants` - this view and its children aren't important for autofill
* - `yes` - is important for autofill
* - `yesExcludeDescendants` - this view is important for autofill but its children aren't
*/
importantForAutofill?:
| 'auto'
| 'no'
| 'noExcludeDescendants'
| 'yes'
| 'yesExcludeDescendants'
| undefined;
/**
* When false, if there is a small amount of space available around a text input (e.g. landscape orientation on a phone),
* the OS may choose to have the user edit the text inside of a full screen text input mode.
* When true, this feature is disabled and users will always edit the text directly inside of the text input.
* Defaults to false.
*/
disableFullscreenUI?: boolean | undefined;
/**
* If defined, the provided image resource will be rendered on the left.
*/
inlineImageLeft?: string | undefined;
/**
* Padding between the inline image, if any, and the text input itself.
*/
inlineImagePadding?: number | undefined;
/**
* Sets the number of lines for a TextInput.
* Use it with multiline set to true to be able to fill the lines.
*/
numberOfLines?: number | undefined;
/**
* Sets the return key to the label. Use it instead of `returnKeyType`.
* @platform android
*/
returnKeyLabel?: string | undefined;
/**
* Set text break strategy on Android API Level 23+, possible values are simple, highQuality, balanced
* The default value is simple.
*/
textBreakStrategy?: 'simple' | 'highQuality' | 'balanced' | undefined;
/**
* The color of the textInput underline.
*/
underlineColorAndroid?: ColorValue | undefined;
/**
* Vertically align text when `multiline` is set to true
*/
textAlignVertical?: 'auto' | 'top' | 'bottom' | 'center' | undefined;
/**
* When false, it will prevent the soft keyboard from showing when the field is focused. The default value is true
*/
showSoftInputOnFocus?: boolean | undefined;
/**
* Vertically align text when `multiline` is set to true
*/
verticalAlign?: 'auto' | 'top' | 'bottom' | 'middle' | undefined;
}
/**
* @see TextInputProps.onFocus
*/
export interface TextInputFocusEventData extends TargetedEvent {
text: string;
eventCount: number;
}
/**
* @see TextInputProps.onScroll
*/
export interface TextInputScrollEventData {
contentOffset: {x: number; y: number};
}
/**
* @see TextInputProps.onSelectionChange
*/
export interface TextInputSelectionChangeEventData extends TargetedEvent {
selection: {
start: number;
end: number;
};
}
/**
* @see TextInputProps.onKeyPress
*/
export interface TextInputKeyPressEventData {
key: string;
}
/**
* @see TextInputProps.onChange
*/
export interface TextInputChangeEventData extends TargetedEvent {
eventCount: number;
text: string;
}
/**
* @see TextInputProps.onContentSizeChange
*/
export interface TextInputContentSizeChangeEventData {
contentSize: {width: number; height: number};
}
/**
* @see TextInputProps.onEndEditing
*/
export interface TextInputEndEditingEventData {
text: string;
}
/**
* @see TextInputProps.onSubmitEditing
*/
export interface TextInputSubmitEditingEventData {
text: string;
}
/**
* @see TextInputProps.onTextInput
*/
export interface TextInputTextInputEventData {
text: string;
previousText: string;
range: {start: number; end: number};
}
/**
* @see https://reactnative.dev/docs/textinput#props
*/
export interface TextInputProps
extends ViewProps,
TextInputIOSProps,
TextInputAndroidProps,
AccessibilityProps {
/**
* Specifies whether fonts should scale to respect Text Size accessibility settings.
* The default is `true`.
*/
allowFontScaling?: boolean | undefined;
/**
* Can tell TextInput to automatically capitalize certain characters.
* characters: all characters,
* words: first letter of each word
* sentences: first letter of each sentence (default)
* none: don't auto capitalize anything
*
* https://reactnative.dev/docs/textinput#autocapitalize
*/
autoCapitalize?: 'none' | 'sentences' | 'words' | 'characters' | undefined;
/**
* Specifies autocomplete hints for the system, so it can provide autofill.
* On Android, the system will always attempt to offer autofill by using heuristics to identify the type of content.
* To disable autocomplete, set autoComplete to off.
*
* The following values work across platforms:
*
* - `additional-name`
* - `address-line1`
* - `address-line2`
* - `cc-number`
* - `country`
* - `current-password`
* - `email`
* - `family-name`
* - `given-name`
* - `honorific-prefix`
* - `honorific-suffix`
* - `name`
* - `new-password`
* - `off`
* - `one-time-code`
* - `postal-code`
* - `street-address`
* - `tel`
* - `username`
*
* The following values work on iOS only:
*
* - `nickname`
* - `organization`
* - `organization-title`
* - `url`
*
* The following values work on Android only:
*
* - `birthdate-day`
* - `birthdate-full`
* - `birthdate-month`
* - `birthdate-year`
* - `cc-csc`
* - `cc-exp`
* - `cc-exp-day`
* - `cc-exp-month`
* - `cc-exp-year`
* - `gender`
* - `name-family`
* - `name-given`
* - `name-middle`
* - `name-middle-initial`
* - `name-prefix`
* - `name-suffix`
* - `password`
* - `password-new`
* - `postal-address`
* - `postal-address-country`
* - `postal-address-extended`
* - `postal-address-extended-postal-code`
* - `postal-address-locality`
* - `postal-address-region`
* - `sms-otp`
* - `tel-country-code`
* - `tel-national`
* - `tel-device`
* - `username-new`
*/
autoComplete?:
| 'additional-name'
| 'address-line1'
| 'address-line2'
| 'birthdate-day'
| 'birthdate-full'
| 'birthdate-month'
| 'birthdate-year'
| 'cc-csc'
| 'cc-exp'
| 'cc-exp-day'
| 'cc-exp-month'
| 'cc-exp-year'
| 'cc-number'
| 'cc-name'
| 'cc-given-name'
| 'cc-middle-name'
| 'cc-family-name'
| 'cc-type'
| 'country'
| 'current-password'
| 'email'
| 'family-name'
| 'gender'
| 'given-name'
| 'honorific-prefix'
| 'honorific-suffix'
| 'name'
| 'name-family'
| 'name-given'
| 'name-middle'
| 'name-middle-initial'
| 'name-prefix'
| 'name-suffix'
| 'new-password'
| 'nickname'
| 'one-time-code'
| 'organization'
| 'organization-title'
| 'password'
| 'password-new'
| 'postal-address'
| 'postal-address-country'
| 'postal-address-extended'
| 'postal-address-extended-postal-code'
| 'postal-address-locality'
| 'postal-address-region'
| 'postal-code'
| 'street-address'
| 'sms-otp'
| 'tel'
| 'tel-country-code'
| 'tel-national'
| 'tel-device'
| 'url'
| 'username'
| 'username-new'
| 'off'
| undefined;
/**
* If false, disables auto-correct.
* The default value is true.
*/
autoCorrect?: boolean | undefined;
/**
* If true, focuses the input on componentDidMount.
* The default value is false.
*/
autoFocus?: boolean | undefined;
/**
* If true, the text field will blur when submitted.
* The default value is true.
*/
blurOnSubmit?: boolean | undefined;
/**
* If true, caret is hidden. The default value is false.
*/
caretHidden?: boolean | undefined;
/**
* If true, context menu is hidden. The default value is false.
*/
contextMenuHidden?: boolean | undefined;
/**
* Provides an initial value that will change when the user starts typing.
* Useful for simple use-cases where you don't want to deal with listening to events
* and updating the value prop to keep the controlled state in sync.
*/
defaultValue?: string | undefined;
/**
* If false, text is not editable. The default value is true.
*/
editable?: boolean | undefined;
/**
* enum("default", 'numeric', 'email-address', "ascii-capable", 'numbers-and-punctuation', 'url', 'number-pad', 'phone-pad', 'name-phone-pad',
* 'decimal-pad', 'twitter', 'web-search', 'visible-password')
* Determines which keyboard to open, e.g.numeric.
* The following values work across platforms: - default - numeric - email-address - phone-pad
* The following values work on iOS: - ascii-capable - numbers-and-punctuation - url - number-pad - name-phone-pad - decimal-pad - twitter - web-search
* The following values work on Android: - visible-password
*/
keyboardType?: KeyboardTypeOptions | undefined;
/**
* Works like the inputmode attribute in HTML, it determines which keyboard to open, e.g. numeric and has precedence over keyboardType.
*/
inputMode?: InputModeOptions | undefined;
/**
* Limits the maximum number of characters that can be entered.
* Use this instead of implementing the logic in JS to avoid flicker.
*/
maxLength?: number | undefined;
/**
* If true, the text input can be multiple lines. The default value is false.
*/
multiline?: boolean | undefined;
/**
* Callback that is called when the text input is blurred
*/
onBlur?:
| ((e: NativeSyntheticEvent<TextInputFocusEventData>) => void)
| undefined;
/**
* Callback that is called when the text input's text changes.
*/
onChange?:
| ((e: NativeSyntheticEvent<TextInputChangeEventData>) => void)
| undefined;
/**
* Callback that is called when the text input's text changes.
* Changed text is passed as an argument to the callback handler.
*/
onChangeText?: ((text: string) => void) | undefined;
/**
* Callback that is called when the text input's content size changes.
* This will be called with
* `{ nativeEvent: { contentSize: { width, height } } }`.
*
* Only called for multiline text inputs.
*/
onContentSizeChange?:
| ((e: NativeSyntheticEvent<TextInputContentSizeChangeEventData>) => void)
| undefined;
/**
* Callback that is called when text input ends.
*/
onEndEditing?:
| ((e: NativeSyntheticEvent<TextInputEndEditingEventData>) => void)
| undefined;
/**
* Called when a single tap gesture is detected.
*/
onPress?: ((e: NativeSyntheticEvent<NativeTouchEvent>) => void) | undefined;
/**
* Callback that is called when a touch is engaged.
*/
onPressIn?: ((e: NativeSyntheticEvent<NativeTouchEvent>) => void) | undefined;
/**
* Callback that is called when a touch is released.
*/
onPressOut?:
| ((e: NativeSyntheticEvent<NativeTouchEvent>) => void)
| undefined;
/**
* Callback that is called when the text input is focused
*/
onFocus?:
| ((e: NativeSyntheticEvent<TextInputFocusEventData>) => void)
| undefined;
/**
* Callback that is called when the text input selection is changed.
*/
onSelectionChange?:
| ((e: NativeSyntheticEvent<TextInputSelectionChangeEventData>) => void)
| undefined;
/**
* Callback that is called when the text input's submit button is pressed.
*/
onSubmitEditing?:
| ((e: NativeSyntheticEvent<TextInputSubmitEditingEventData>) => void)
| undefined;
/**
* Callback that is called on new text input with the argument
* `{ nativeEvent: { text, previousText, range: { start, end } } }`.
*
* This prop requires multiline={true} to be set.
*/
onTextInput?:
| ((e: NativeSyntheticEvent<TextInputTextInputEventData>) => void)
| undefined;
/**
* Invoked on content scroll with
* `{ nativeEvent: { contentOffset: { x, y } } }`.
*
* May also contain other properties from ScrollEvent but on Android contentSize is not provided for performance reasons.
*/
onScroll?:
| ((e: NativeSyntheticEvent<TextInputScrollEventData>) => void)
| undefined;
/**
* Callback that is called when a key is pressed.
* This will be called with
* `{ nativeEvent: { key: keyValue } }`
* where keyValue is 'Enter' or 'Backspace' for respective keys and the typed-in character otherwise including ' ' for space.
*
* Fires before onChange callbacks.
* Note: on Android only the inputs from soft keyboard are handled, not the hardware keyboard inputs.
*/
onKeyPress?:
| ((e: NativeSyntheticEvent<TextInputKeyPressEventData>) => void)
| undefined;
/**
* The string that will be rendered before text input has been entered
*/
placeholder?: string | undefined;
/**
* The text color of the placeholder string
*/
placeholderTextColor?: ColorValue | undefined;
/**
* If `true`, text is not editable. The default value is `false`.
*/
readOnly?: boolean | undefined;
/**
* enum('default', 'go', 'google', 'join', 'next', 'route', 'search', 'send', 'yahoo', 'done', 'emergency-call')
* Determines how the return key should look.
*/
returnKeyType?: ReturnKeyTypeOptions | undefined;
/**
* Determines what text should be shown to the return key on virtual keyboards.
* Has precedence over the returnKeyType prop.
*/
enterKeyHint?: EnterKeyHintTypeOptions | undefined;
/**
* If true, the text input obscures the text entered so that sensitive text like passwords stay secure.
* The default value is false.
*/
secureTextEntry?: boolean | undefined;
/**
* If true, all text will automatically be selected on focus
*/
selectTextOnFocus?: boolean | undefined;
/**
* The start and end of the text input's selection. Set start and end to
* the same value to position the cursor.
*/
selection?: {start: number; end?: number | undefined} | undefined;
/**
* The highlight (and cursor on ios) color of the text input
*/
selectionColor?: ColorValue | undefined;
/**
* Styles
*/
style?: StyleProp<TextStyle> | undefined;
/**
* Align the input text to the left, center, or right sides of the input field.
*/
textAlign?: 'left' | 'center' | 'right' | undefined;
/**
* Used to locate this view in end-to-end tests
*/
testID?: string | undefined;
/**
* Used to connect to an InputAccessoryView. Not part of react-natives documentation, but present in examples and
* code.
* See https://reactnative.dev/docs/inputaccessoryview for more information.
*/
inputAccessoryViewID?: string | undefined;
/**
* The value to show for the text input. TextInput is a controlled component,
* which means the native value will be forced to match this value prop if provided.
* For most uses this works great, but in some cases this may cause flickering - one common cause is preventing edits by keeping value the same.
* In addition to simply setting the same value, either set editable={false},
* or set/update maxLength to prevent unwanted edits without flicker.
*/
value?: string | undefined;
/**
* Specifies largest possible scale a font can reach when allowFontScaling is enabled. Possible values:
* - null/undefined (default): inherit from the parent node or the global default (0)
* - 0: no max, ignore parent/global default
* - >= 1: sets the maxFontSizeMultiplier of this node to this value
*/
maxFontSizeMultiplier?: number | null | undefined;
}
/**
* This class is responsible for coordinating the "focused"
* state for TextInputs. All calls relating to the keyboard
* should be funneled through here
*/
interface TextInputState {
/**
* @deprecated Use currentlyFocusedInput
* Returns the ID of the currently focused text field, if one exists
* If no text field is focused it returns null
*/
currentlyFocusedField(): number;
/**
* Returns the ref of the currently focused text field, if one exists
* If no text field is focused it returns null
*/
currentlyFocusedInput(): React.ElementRef<HostComponent<unknown>>;
/**
* @param textField ref of the text field to focus
* Focuses the specified text field
* noop if the text field was already focused
*/
focusTextInput(textField?: React.ElementRef<HostComponent<unknown>>): void;
/**
* @param textField ref of the text field to focus
* Unfocuses the specified text field
* noop if it wasn't focused
*/
blurTextInput(textField?: React.ElementRef<HostComponent<unknown>>): void;
}
/**
* @see https://reactnative.dev/docs/textinput#methods
*/
declare class TextInputComponent extends React.Component<TextInputProps> {}
declare const TextInputBase: Constructor<NativeMethods> &
Constructor<TimerMixin> &
typeof TextInputComponent;
export class TextInput extends TextInputBase {
/**
* Access the current focus state.
*/
static State: TextInputState;
/**
* Returns if the input is currently focused.
*/
isFocused: () => boolean;
/**
* Removes all text from the input.
*/
clear: () => void;
/**
* Sets the start and end positions of text selection.
*/
setSelection: (start: number, end: number) => void;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,29 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
*/
import type {Int32} from '../../Types/CodegenTypes';
import * as React from 'react';
export interface TextInputNativeCommands<T> {
+focus: (viewRef: React.ElementRef<T>) => void;
+blur: (viewRef: React.ElementRef<T>) => void;
+setTextAndSelection: (
viewRef: React.ElementRef<T>,
mostRecentEventCount: Int32,
value: ?string, // in theory this is nullable
start: Int32,
end: Int32,
) => void;
}
const supportedCommands = ['focus', 'blur', 'setTextAndSelection'];
export default supportedCommands;

View File

@@ -0,0 +1,214 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @flow strict-local
*/
// This class is responsible for coordinating the "focused" state for
// TextInputs. All calls relating to the keyboard should be funneled
// through here.
import type {
HostComponent,
MeasureInWindowOnSuccessCallback,
MeasureLayoutOnSuccessCallback,
MeasureOnSuccessCallback,
} from '../../Renderer/shims/ReactNativeTypes';
import {Commands as AndroidTextInputCommands} from '../../Components/TextInput/AndroidTextInputNativeComponent';
import {Commands as iOSTextInputCommands} from '../../Components/TextInput/RCTSingelineTextInputNativeComponent';
const {findNodeHandle} = require('../../ReactNative/RendererProxy');
const Platform = require('../../Utilities/Platform');
const React = require('react');
type ComponentRef = React.ElementRef<HostComponent<mixed>>;
let currentlyFocusedInputRef: ?ComponentRef = null;
const inputs = new Set<{
blur(): void,
focus(): void,
measure(callback: MeasureOnSuccessCallback): void,
measureInWindow(callback: MeasureInWindowOnSuccessCallback): void,
measureLayout(
relativeToNativeNode: number | React.ElementRef<HostComponent<mixed>>,
onSuccess: MeasureLayoutOnSuccessCallback,
onFail?: () => void,
): void,
setNativeProps(nativeProps: {...}): void,
}>();
function currentlyFocusedInput(): ?ComponentRef {
return currentlyFocusedInputRef;
}
/**
* Returns the ID of the currently focused text field, if one exists
* If no text field is focused it returns null
*/
function currentlyFocusedField(): ?number {
if (__DEV__) {
console.error(
'currentlyFocusedField is deprecated and will be removed in a future release. Use currentlyFocusedInput',
);
}
return findNodeHandle(currentlyFocusedInputRef);
}
function focusInput(textField: ?ComponentRef): void {
if (currentlyFocusedInputRef !== textField && textField != null) {
currentlyFocusedInputRef = textField;
}
}
function blurInput(textField: ?ComponentRef): void {
if (currentlyFocusedInputRef === textField && textField != null) {
currentlyFocusedInputRef = null;
}
}
function focusField(textFieldID: ?number): void {
if (__DEV__) {
console.error('focusField no longer works. Use focusInput');
}
return;
}
function blurField(textFieldID: ?number) {
if (__DEV__) {
console.error('blurField no longer works. Use blurInput');
}
return;
}
/**
* @param {number} TextInputID id of the text field to focus
* Focuses the specified text field
* noop if the text field was already focused or if the field is not editable
*/
function focusTextInput(textField: ?ComponentRef) {
if (typeof textField === 'number') {
if (__DEV__) {
console.error(
'focusTextInput must be called with a host component. Passing a react tag is deprecated.',
);
}
return;
}
if (textField != null) {
const fieldCanBeFocused =
currentlyFocusedInputRef !== textField &&
// $FlowFixMe - `currentProps` is missing in `NativeMethods`
textField.currentProps?.editable !== false;
if (!fieldCanBeFocused) {
return;
}
focusInput(textField);
if (Platform.OS === 'ios') {
// This isn't necessarily a single line text input
// But commands don't actually care as long as the thing being passed in
// actually has a command with that name. So this should work with single
// and multiline text inputs. Ideally we'll merge them into one component
// in the future.
iOSTextInputCommands.focus(textField);
} else if (Platform.OS === 'android') {
AndroidTextInputCommands.focus(textField);
}
}
}
/**
* @param {number} textFieldID id of the text field to unfocus
* Unfocuses the specified text field
* noop if it wasn't focused
*/
function blurTextInput(textField: ?ComponentRef) {
if (typeof textField === 'number') {
if (__DEV__) {
console.error(
'blurTextInput must be called with a host component. Passing a react tag is deprecated.',
);
}
return;
}
if (currentlyFocusedInputRef === textField && textField != null) {
blurInput(textField);
if (Platform.OS === 'ios') {
// This isn't necessarily a single line text input
// But commands don't actually care as long as the thing being passed in
// actually has a command with that name. So this should work with single
// and multiline text inputs. Ideally we'll merge them into one component
// in the future.
iOSTextInputCommands.blur(textField);
} else if (Platform.OS === 'android') {
AndroidTextInputCommands.blur(textField);
}
}
}
function registerInput(textField: ComponentRef) {
if (typeof textField === 'number') {
if (__DEV__) {
console.error(
'registerInput must be called with a host component. Passing a react tag is deprecated.',
);
}
return;
}
inputs.add(textField);
}
function unregisterInput(textField: ComponentRef) {
if (typeof textField === 'number') {
if (__DEV__) {
console.error(
'unregisterInput must be called with a host component. Passing a react tag is deprecated.',
);
}
return;
}
inputs.delete(textField);
}
function isTextInput(textField: ComponentRef): boolean {
if (typeof textField === 'number') {
if (__DEV__) {
console.error(
'isTextInput must be called with a host component. Passing a react tag is deprecated.',
);
}
return false;
}
return inputs.has(textField);
}
module.exports = {
currentlyFocusedInput,
focusInput,
blurInput,
currentlyFocusedField,
focusField,
blurField,
focusTextInput,
blurTextInput,
registerInput,
unregisterInput,
isTextInput,
};