@expo/ui 56.0.16 → 56.0.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/android/build.gradle +2 -2
  3. package/android/src/main/java/expo/modules/ui/ExpoUIModule.kt +40 -6
  4. package/android/src/main/java/expo/modules/ui/HostView.kt +0 -2
  5. package/android/src/main/java/expo/modules/ui/ModifierRegistry.kt +20 -0
  6. package/android/src/main/java/expo/modules/ui/RNHostView.kt +182 -6
  7. package/android/src/main/java/expo/modules/ui/textfield/BasicTextField.kt +203 -0
  8. package/android/src/main/java/expo/modules/ui/{TextFieldView.kt → textfield/TextField.kt} +34 -248
  9. package/android/src/main/java/expo/modules/ui/textfield/TextFieldShared.kt +299 -0
  10. package/build/State/useNativeState.d.ts +8 -3
  11. package/build/State/useNativeState.d.ts.map +1 -1
  12. package/build/community/pager-view/PagerView.android.d.ts.map +1 -1
  13. package/build/jetpack-compose/TextField/BasicTextField.d.ts +36 -0
  14. package/build/jetpack-compose/TextField/BasicTextField.d.ts.map +1 -0
  15. package/build/jetpack-compose/TextField/TextField.d.ts +131 -0
  16. package/build/jetpack-compose/TextField/TextField.d.ts.map +1 -0
  17. package/build/jetpack-compose/TextField/index.d.ts +3 -244
  18. package/build/jetpack-compose/TextField/index.d.ts.map +1 -1
  19. package/build/jetpack-compose/TextField/shared.d.ts +171 -0
  20. package/build/jetpack-compose/TextField/shared.d.ts.map +1 -0
  21. package/build/jetpack-compose/index.d.ts +1 -1
  22. package/build/jetpack-compose/index.d.ts.map +1 -1
  23. package/build/jetpack-compose/modifiers/index.d.ts +11 -0
  24. package/build/jetpack-compose/modifiers/index.d.ts.map +1 -1
  25. package/build/swift-ui/Image/index.d.ts +3 -1
  26. package/build/swift-ui/Image/index.d.ts.map +1 -1
  27. package/build/swift-ui/modifiers/index.d.ts +33 -4
  28. package/build/swift-ui/modifiers/index.d.ts.map +1 -1
  29. package/build/universal/TextInput/index.android.d.ts.map +1 -1
  30. package/build/universal/TextInput/types.d.ts +5 -1
  31. package/build/universal/TextInput/types.d.ts.map +1 -1
  32. package/expo-module.config.json +1 -1
  33. package/ios/ImageView.swift +1 -5
  34. package/ios/Modifiers/ImageScaleModifier.swift +29 -0
  35. package/ios/Modifiers/OnGeometryChangeModifier.swift +8 -16
  36. package/ios/Modifiers/ViewModifierRegistry.swift +32 -0
  37. package/local-maven-repo/expo/modules/ui/expo.modules.ui/{56.0.16/expo.modules.ui-56.0.16-sources.jar → 56.0.17/expo.modules.ui-56.0.17-sources.jar} +0 -0
  38. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.17/expo.modules.ui-56.0.17-sources.jar.md5 +1 -0
  39. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.17/expo.modules.ui-56.0.17-sources.jar.sha1 +1 -0
  40. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.17/expo.modules.ui-56.0.17-sources.jar.sha256 +1 -0
  41. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.17/expo.modules.ui-56.0.17-sources.jar.sha512 +1 -0
  42. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.17/expo.modules.ui-56.0.17.aar +0 -0
  43. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.17/expo.modules.ui-56.0.17.aar.md5 +1 -0
  44. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.17/expo.modules.ui-56.0.17.aar.sha1 +1 -0
  45. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.17/expo.modules.ui-56.0.17.aar.sha256 +1 -0
  46. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.17/expo.modules.ui-56.0.17.aar.sha512 +1 -0
  47. package/local-maven-repo/expo/modules/ui/expo.modules.ui/{56.0.16/expo.modules.ui-56.0.16.module → 56.0.17/expo.modules.ui-56.0.17.module} +22 -22
  48. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.17/expo.modules.ui-56.0.17.module.md5 +1 -0
  49. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.17/expo.modules.ui-56.0.17.module.sha1 +1 -0
  50. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.17/expo.modules.ui-56.0.17.module.sha256 +1 -0
  51. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.17/expo.modules.ui-56.0.17.module.sha512 +1 -0
  52. package/local-maven-repo/expo/modules/ui/expo.modules.ui/{56.0.16/expo.modules.ui-56.0.16.pom → 56.0.17/expo.modules.ui-56.0.17.pom} +1 -1
  53. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.17/expo.modules.ui-56.0.17.pom.md5 +1 -0
  54. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.17/expo.modules.ui-56.0.17.pom.sha1 +1 -0
  55. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.17/expo.modules.ui-56.0.17.pom.sha256 +1 -0
  56. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.17/expo.modules.ui-56.0.17.pom.sha512 +1 -0
  57. package/local-maven-repo/expo/modules/ui/expo.modules.ui/maven-metadata.xml +4 -4
  58. package/local-maven-repo/expo/modules/ui/expo.modules.ui/maven-metadata.xml.md5 +1 -1
  59. package/local-maven-repo/expo/modules/ui/expo.modules.ui/maven-metadata.xml.sha1 +1 -1
  60. package/local-maven-repo/expo/modules/ui/expo.modules.ui/maven-metadata.xml.sha256 +1 -1
  61. package/local-maven-repo/expo/modules/ui/expo.modules.ui/maven-metadata.xml.sha512 +1 -1
  62. package/package.json +3 -3
  63. package/src/State/index.fx.ts +4 -1
  64. package/src/State/useNativeState.ts +24 -5
  65. package/src/community/datetime-picker/DateTimePicker.tsx +1 -1
  66. package/src/community/menu/MenuView.ios.tsx +1 -1
  67. package/src/community/pager-view/PagerView.android.tsx +16 -2
  68. package/src/community/pager-view/PagerView.ios.tsx +1 -1
  69. package/src/community/picker/Picker.ios.tsx +1 -1
  70. package/src/community/slider/Slider.ios.tsx +1 -1
  71. package/src/jetpack-compose/TextField/BasicTextField.tsx +118 -0
  72. package/src/jetpack-compose/TextField/TextField.tsx +198 -0
  73. package/src/jetpack-compose/TextField/index.ts +19 -0
  74. package/src/jetpack-compose/TextField/{index.tsx → shared.ts} +71 -203
  75. package/src/jetpack-compose/index.ts +6 -0
  76. package/src/jetpack-compose/modifiers/index.ts +13 -0
  77. package/src/swift-ui/BottomSheet/index.tsx +1 -1
  78. package/src/swift-ui/Image/index.tsx +12 -3
  79. package/src/swift-ui/modifiers/index.ts +42 -5
  80. package/src/universal/TextInput/index.android.tsx +26 -60
  81. package/src/universal/TextInput/types.ts +5 -1
  82. package/android/src/main/java/expo/modules/ui/ShadowNodeSyncFlush.kt +0 -28
  83. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.16/expo.modules.ui-56.0.16-sources.jar.md5 +0 -1
  84. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.16/expo.modules.ui-56.0.16-sources.jar.sha1 +0 -1
  85. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.16/expo.modules.ui-56.0.16-sources.jar.sha256 +0 -1
  86. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.16/expo.modules.ui-56.0.16-sources.jar.sha512 +0 -1
  87. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.16/expo.modules.ui-56.0.16.aar +0 -0
  88. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.16/expo.modules.ui-56.0.16.aar.md5 +0 -1
  89. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.16/expo.modules.ui-56.0.16.aar.sha1 +0 -1
  90. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.16/expo.modules.ui-56.0.16.aar.sha256 +0 -1
  91. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.16/expo.modules.ui-56.0.16.aar.sha512 +0 -1
  92. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.16/expo.modules.ui-56.0.16.module.md5 +0 -1
  93. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.16/expo.modules.ui-56.0.16.module.sha1 +0 -1
  94. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.16/expo.modules.ui-56.0.16.module.sha256 +0 -1
  95. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.16/expo.modules.ui-56.0.16.module.sha512 +0 -1
  96. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.16/expo.modules.ui-56.0.16.pom.md5 +0 -1
  97. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.16/expo.modules.ui-56.0.16.pom.sha1 +0 -1
  98. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.16/expo.modules.ui-56.0.16.pom.sha256 +0 -1
  99. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.16/expo.modules.ui-56.0.16.pom.sha512 +0 -1
@@ -1 +1 @@
1
- 06d44b3caa511e0c357fa5a4b97c3867
1
+ 60c5694e01fc3b8dcd52745fd34646eb
@@ -1 +1 @@
1
- 6b09b188d3943a03a462cc08d80212d62490d2b9
1
+ 86afe3595463910ac648dbece60ea85603f093da
@@ -1 +1 @@
1
- 680aeda3449ab8b21e06cec91465124d63053367f1be0fa5c6b005526a0eccf4
1
+ e33fc63e4f06dfa13f99ce5b5ceafeaf1d4045473ecbbe42799c66be3c5a1bc7
@@ -1 +1 @@
1
- 3a7cfc9313dacce167a1c0e9ff4519e357d5043205c6c16e47365cf5c5db3ea7b5660c5981e619f5e3d3f2079768975ba35d8eea6adb0d2bd9afd9543a4787d0
1
+ 8a94e8065a8cf5abcbc83a6d2ce2d927133a4670a8313b921b7369f6793cede644c762fefc3807c9bc2d7bfdf15aeccc183cb4c9b383094576455cbe6d8e0fa6
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@expo/ui",
3
- "version": "56.0.16",
3
+ "version": "56.0.17",
4
4
  "description": "A collection of UI components",
5
5
  "sideEffects": [
6
6
  "*.fx.js"
@@ -95,7 +95,7 @@
95
95
  "@types/react": "~19.2.0",
96
96
  "react-native-reanimated": "4.3.1",
97
97
  "react-native-worklets": "0.8.3",
98
- "expo": "56.0.9",
98
+ "expo": "56.0.10",
99
99
  "expo-module-scripts": "56.0.3"
100
100
  },
101
101
  "jest": {
@@ -124,7 +124,7 @@
124
124
  "optional": true
125
125
  }
126
126
  },
127
- "gitHead": "175f1e78e3444ca99ddea473faea6777a0656668",
127
+ "gitHead": "b1e94a5c1c5b19472a42ca25752a3533699bc46a",
128
128
  "scripts": {
129
129
  "build": "expo-module build",
130
130
  "clean": "expo-module clean",
@@ -41,7 +41,8 @@ function registerSharedObjectSerializer(): void {
41
41
  unpack: (packed) => {
42
42
  'worklet';
43
43
  const obj = (globalThis as any).expo.SharedObject.__resolveInWorklet(packed.objectId);
44
- // Define .value property if the object has getValue/setValue (e.g. ObservableState)
44
+ // Define .value plus the get/set accessors if the object has
45
+ // getValue/setValue (e.g. ObservableState)
45
46
  if (typeof obj.getValue === 'function' && typeof obj.setValue === 'function') {
46
47
  Object.defineProperty(obj, 'value', {
47
48
  get() {
@@ -51,6 +52,8 @@ function registerSharedObjectSerializer(): void {
51
52
  obj.setValue({ value: v });
52
53
  },
53
54
  });
55
+ obj.get = () => obj.getValue();
56
+ obj.set = (v: any) => obj.setValue({ value: v });
54
57
  }
55
58
  return obj;
56
59
  },
@@ -20,6 +20,16 @@ export type ObservableState<T> = SharedObject & {
20
20
  */
21
21
  value: T;
22
22
 
23
+ /**
24
+ * Reads the current value. A React Compiler compliant alternative to reading `.value`
25
+ */
26
+ get(): T;
27
+
28
+ /**
29
+ * Writes a new value. A React Compiler-compliant alternative to assigning `.value`
30
+ */
31
+ set(value: T): void;
32
+
23
33
  /**
24
34
  * A single listener invoked on the native UI runtime whenever the value changes
25
35
  * (after iOS `didSet` and Android's setter). Assigning replaces the previous
@@ -38,9 +48,6 @@ export type ObservableState<T> = SharedObject & {
38
48
  * 'worklet';
39
49
  * console.log('changed to', value);
40
50
  * };
41
- * return () => {
42
- * state.onChange = null;
43
- * };
44
51
  * }, []);
45
52
  * ```
46
53
  */
@@ -65,10 +72,13 @@ type NativeObservableState = {
65
72
  getValue(): unknown;
66
73
  setValue(v: { value: unknown }): void;
67
74
  setOnChange(callback: object | null): void;
75
+ get?: () => unknown;
76
+ set?: (value: unknown) => void;
68
77
  };
69
78
 
70
79
  /**
71
- * Adds a `value` property that delegates to the native `getValue`/`setValue` functions.
80
+ * Adds a `value` property plus `get`/`set` methods that delegate to the native
81
+ * `getValue`/`setValue` functions.
72
82
  */
73
83
  function defineValueProperty(state: NativeObservableState): void {
74
84
  Object.defineProperty(state, 'value', {
@@ -79,6 +89,8 @@ function defineValueProperty(state: NativeObservableState): void {
79
89
  state.setValue({ value: v });
80
90
  },
81
91
  });
92
+ state.get = () => state.getValue();
93
+ state.set = (v: unknown) => state.setValue({ value: v });
82
94
  }
83
95
 
84
96
  /**
@@ -96,7 +108,14 @@ function defineOnChangeProperty(state: NativeObservableState): void {
96
108
  set(fn: ((value: unknown) => void) | null | undefined) {
97
109
  if (!fn) {
98
110
  currentFn = null;
99
- state.setOnChange(null);
111
+ try {
112
+ state.setOnChange(null);
113
+ } catch {
114
+ // On unmount the shared object is often released before this cleanup
115
+ // runs (useReleasingSharedObject releases it earlier in the component),
116
+ // so setOnChange throws "already released". Clearing a listener on a
117
+ // gone object is a no-op, so ignore it rather than crash teardown.
118
+ }
100
119
  return;
101
120
  }
102
121
  if (!worklets) {
@@ -87,7 +87,7 @@ export function DateTimePicker(props: DateTimePickerProps) {
87
87
  };
88
88
 
89
89
  return (
90
- <Host matchContents={{ vertical: true }} style={style}>
90
+ <Host matchContents={{ vertical: true }} style={style} ignoreSafeArea="all">
91
91
  <DatePicker {...iosProps} />
92
92
  </Host>
93
93
  );
@@ -135,7 +135,7 @@ export function MenuView(props: MenuComponentProps & { ref?: React.Ref<MenuCompo
135
135
  );
136
136
 
137
137
  return (
138
- <Host matchContents style={style} testID={testID}>
138
+ <Host matchContents style={style} testID={testID} ignoreSafeArea="all">
139
139
  {shouldOpenOnLongPress ? (
140
140
  <ContextMenu>
141
141
  <ContextMenu.Trigger>{trigger}</ContextMenu.Trigger>
@@ -8,7 +8,7 @@ import {
8
8
  useState,
9
9
  type ReactElement,
10
10
  } from 'react';
11
- import { StyleSheet } from 'react-native';
11
+ import { StyleSheet, View } from 'react-native';
12
12
 
13
13
  import { wrapNativeEvent, type PagerViewProps } from './types';
14
14
  import { worklets } from '../../State';
@@ -43,6 +43,13 @@ export function PagerView(props: PagerViewProps) {
43
43
  setScrollEnabledState(scrollEnabled);
44
44
  }, [scrollEnabled]);
45
45
 
46
+ // All pages share the same (0,0) origin in RN's layout — Compose, not Yoga,
47
+ // applies the per-page offset — so off-screen pages overlap the visible one in
48
+ // RN's coordinate space and can steal its touches (#46386). Track the settled
49
+ // page and make only it interactive; non-settled pages are `pointerEvents`
50
+ // "none" so hit-testing resolves taps to the page actually on screen.
51
+ const [settledPage, setSettledPage] = useState(initialPage);
52
+
46
53
  // Synthesize pager-view's `idle | dragging | settling` from Compose's raw
47
54
  // signals: `isScrollInProgress` (drag or snap-animation in flight) plus
48
55
  // drag interactions (start/stop/cancel).
@@ -73,7 +80,9 @@ export function PagerView(props: PagerViewProps) {
73
80
  .filter((child): child is ReactElement => isValidElement(child))
74
81
  .map((child, index) => (
75
82
  <RNHostView key={child.key ?? String(index)} modifiers={[fillMaxSize()]}>
76
- {child}
83
+ <View style={styles.page} pointerEvents={index === settledPage ? 'auto' : 'none'}>
84
+ {child}
85
+ </View>
77
86
  </RNHostView>
78
87
  ));
79
88
 
@@ -101,6 +110,7 @@ export function PagerView(props: PagerViewProps) {
101
110
  beyondViewportPageCount={offscreenPageLimit}
102
111
  modifiers={pagerModifiers}
103
112
  onSettledPageChange={(page) => {
113
+ setSettledPage(page);
104
114
  onPageSelected?.(wrapNativeEvent({ position: page }));
105
115
  }}
106
116
  onPageScroll={pageScrollHandler}
@@ -222,3 +232,7 @@ function warnAboutStringBorderRadiusOnce(key: string, value: string): void {
222
232
  `Use a numeric pixel value, or omit the style key.`
223
233
  );
224
234
  }
235
+
236
+ const styles = StyleSheet.create({
237
+ page: { flex: 1 },
238
+ });
@@ -213,7 +213,7 @@ export function PagerView(props: PagerViewProps) {
213
213
  ];
214
214
 
215
215
  return (
216
- <Host style={style ?? { flex: 1 }} {...passthrough}>
216
+ <Host style={style ?? { flex: 1 }} ignoreSafeArea="all" {...passthrough}>
217
217
  <ScrollView axes="horizontal" showsIndicators={false} modifiers={modifiers}>
218
218
  <LazyHStack spacing={0} modifiers={[scrollTargetLayout()]}>
219
219
  {pages}
@@ -41,7 +41,7 @@ export function Picker<T extends PickerItemValue>(props: PickerProps<T>) {
41
41
  }));
42
42
 
43
43
  return (
44
- <Host matchContents={{ vertical: true }} style={style}>
44
+ <Host matchContents={{ vertical: true }} style={style} ignoreSafeArea="all">
45
45
  <SwiftUIPicker
46
46
  modifiers={modifiers}
47
47
  selection={selectedValue}
@@ -32,7 +32,7 @@ export function Slider(props: SliderProps) {
32
32
  modifiers.push(tintModifier(minimumTrackTintColor as string));
33
33
  }
34
34
  return (
35
- <Host matchContents={{ vertical: true }} style={hostStyle}>
35
+ <Host matchContents={{ vertical: true }} style={hostStyle} ignoreSafeArea="all">
36
36
  <SwiftUISlider
37
37
  value={value}
38
38
  min={minimumValue}
@@ -0,0 +1,118 @@
1
+ import { requireNativeView } from 'expo';
2
+ import type { ColorValue } from 'react-native';
3
+
4
+ import {
5
+ type CommonNativeTextFieldProps,
6
+ type CommonTextFieldProperties,
7
+ type TextFieldRef,
8
+ useCommonTextFieldProps,
9
+ } from './shared';
10
+ import { Slot } from '../SlotView';
11
+
12
+ // region Types
13
+
14
+ /**
15
+ * Imperative methods for `BasicTextField`. Identical to {@link TextFieldRef}.
16
+ */
17
+ export type BasicTextFieldRef = TextFieldRef;
18
+
19
+ /**
20
+ * Props for `BasicTextField`. Mirrors Compose's `BasicTextField`: a bare,
21
+ * unstyled text field with no Material chrome (no container, indicator, or
22
+ * built-in padding). Shares {@link CommonTextFieldProperties} with `TextField` and
23
+ * `OutlinedTextField`; use `BasicTextField.DecorationBox` to add your own
24
+ * decoration.
25
+ */
26
+ export type BasicTextFieldProps = CommonTextFieldProperties & {
27
+ /**
28
+ * Color of the text cursor. Maps to Compose's `cursorBrush` via
29
+ * `SolidColor(color)`. Defaults to the theme's primary color
30
+ * (`MaterialTheme.colorScheme.primary`) so it stays visible in light and dark.
31
+ */
32
+ cursorColor?: ColorValue;
33
+ };
34
+
35
+ // endregion Types
36
+
37
+ // region Native
38
+
39
+ type NativeBasicTextFieldProps = Omit<
40
+ BasicTextFieldProps,
41
+ | 'value'
42
+ | 'selection'
43
+ | 'onValueChange'
44
+ | 'onFocusChanged'
45
+ | 'onSelectionChange'
46
+ | 'keyboardActions'
47
+ | 'children'
48
+ > &
49
+ CommonNativeTextFieldProps;
50
+
51
+ const BasicTextFieldNativeView: React.ComponentType<NativeBasicTextFieldProps> = requireNativeView(
52
+ 'ExpoUI',
53
+ 'BasicTextFieldView'
54
+ );
55
+
56
+ const InnerTextFieldNativeView: React.ComponentType<object> = requireNativeView(
57
+ 'ExpoUI',
58
+ 'InnerTextFieldView'
59
+ );
60
+
61
+ const PlaceholderNativeView: React.ComponentType<{ children?: React.ReactNode }> =
62
+ requireNativeView('ExpoUI', 'PlaceholderView');
63
+
64
+ function useTransformedProps(props: BasicTextFieldProps): NativeBasicTextFieldProps {
65
+ return useCommonTextFieldProps(props);
66
+ }
67
+
68
+ // endregion Native
69
+
70
+ // region Slot components
71
+
72
+ /**
73
+ * Wraps the editable text with custom decoration. Maps to Compose's
74
+ * `decorationBox`. Place {@link InnerTextField} inside it where the text
75
+ * should render.
76
+ */
77
+ function DecorationBox(props: { children: React.ReactNode }) {
78
+ return <Slot slotName="decorationBox">{props.children}</Slot>;
79
+ }
80
+
81
+ /**
82
+ * The editable text itself, placed wherever you want it inside
83
+ * {@link DecorationBox}. Maps to the `innerTextField` lambda Compose passes to
84
+ * `decorationBox`.
85
+ */
86
+ function InnerTextField() {
87
+ return <InnerTextFieldNativeView />;
88
+ }
89
+
90
+ /**
91
+ * A placeholder shown only while the field is empty. Place it inside
92
+ * {@link DecorationBox}, typically overlaying {@link InnerTextField}. Its
93
+ * visibility is toggled natively from the field's text, so it stays correct for
94
+ * every change — typing, `clear()`, `setText`, and writes to the `value`
95
+ * observable — without a JS round-trip.
96
+ */
97
+ function Placeholder(props: { children: React.ReactNode }) {
98
+ return <PlaceholderNativeView>{props.children}</PlaceholderNativeView>;
99
+ }
100
+
101
+ // endregion Slot components
102
+
103
+ // region Component
104
+
105
+ /**
106
+ * A bare, unstyled Compose `BasicTextField` with no Material decoration.
107
+ */
108
+ function BasicTextFieldComponent(props: BasicTextFieldProps) {
109
+ return <BasicTextFieldNativeView {...useTransformedProps(props)} />;
110
+ }
111
+
112
+ BasicTextFieldComponent.DecorationBox = DecorationBox;
113
+ BasicTextFieldComponent.InnerTextField = InnerTextField;
114
+ BasicTextFieldComponent.Placeholder = Placeholder;
115
+
116
+ // endregion Component
117
+
118
+ export { BasicTextFieldComponent as BasicTextField };
@@ -0,0 +1,198 @@
1
+ import { requireNativeView } from 'expo';
2
+ import type { ColorValue } from 'react-native';
3
+
4
+ import {
5
+ type CommonNativeTextFieldProps,
6
+ type CommonTextFieldProperties,
7
+ useCommonTextFieldProps,
8
+ } from './shared';
9
+ import { type ObservableState } from '../../State';
10
+ import { parseJSXShape, type ShapeJSXElement, type ShapeRecordProps } from '../Shape';
11
+ import { Slot } from '../SlotView';
12
+
13
+ // region Types
14
+
15
+ /**
16
+ * Colors for `TextField` and `OutlinedTextField`.
17
+ * Maps to `TextFieldColors` in Compose, shared by both variants.
18
+ */
19
+ export type TextFieldColors = {
20
+ focusedTextColor?: ColorValue;
21
+ unfocusedTextColor?: ColorValue;
22
+ disabledTextColor?: ColorValue;
23
+ errorTextColor?: ColorValue;
24
+ focusedContainerColor?: ColorValue;
25
+ unfocusedContainerColor?: ColorValue;
26
+ disabledContainerColor?: ColorValue;
27
+ errorContainerColor?: ColorValue;
28
+ cursorColor?: ColorValue;
29
+ errorCursorColor?: ColorValue;
30
+ focusedIndicatorColor?: ColorValue;
31
+ unfocusedIndicatorColor?: ColorValue;
32
+ disabledIndicatorColor?: ColorValue;
33
+ errorIndicatorColor?: ColorValue;
34
+ focusedLeadingIconColor?: ColorValue;
35
+ unfocusedLeadingIconColor?: ColorValue;
36
+ disabledLeadingIconColor?: ColorValue;
37
+ errorLeadingIconColor?: ColorValue;
38
+ focusedTrailingIconColor?: ColorValue;
39
+ unfocusedTrailingIconColor?: ColorValue;
40
+ disabledTrailingIconColor?: ColorValue;
41
+ errorTrailingIconColor?: ColorValue;
42
+ focusedLabelColor?: ColorValue;
43
+ unfocusedLabelColor?: ColorValue;
44
+ disabledLabelColor?: ColorValue;
45
+ errorLabelColor?: ColorValue;
46
+ focusedPlaceholderColor?: ColorValue;
47
+ unfocusedPlaceholderColor?: ColorValue;
48
+ disabledPlaceholderColor?: ColorValue;
49
+ errorPlaceholderColor?: ColorValue;
50
+ focusedSupportingTextColor?: ColorValue;
51
+ unfocusedSupportingTextColor?: ColorValue;
52
+ disabledSupportingTextColor?: ColorValue;
53
+ errorSupportingTextColor?: ColorValue;
54
+ focusedPrefixColor?: ColorValue;
55
+ unfocusedPrefixColor?: ColorValue;
56
+ disabledPrefixColor?: ColorValue;
57
+ errorPrefixColor?: ColorValue;
58
+ focusedSuffixColor?: ColorValue;
59
+ unfocusedSuffixColor?: ColorValue;
60
+ disabledSuffixColor?: ColorValue;
61
+ errorSuffixColor?: ColorValue;
62
+ };
63
+
64
+ // Material props inlined per variant (not a shared named base) so docs render them directly.
65
+ export type TextFieldProps = CommonTextFieldProperties & {
66
+ /** @default false */
67
+ isError?: boolean;
68
+ /**
69
+ * Shape used for the field's container outline/fill. Use the helpers from
70
+ * `Shape` (for example, `<Shape.Pill />` or `<Shape.RoundedCorner cornerRadii={...} />`).
71
+ * Defaults to the Material `OutlinedTextFieldDefaults.shape`/`TextFieldDefaults.shape`.
72
+ */
73
+ shape?: ShapeJSXElement;
74
+ colors?: TextFieldColors;
75
+ };
76
+
77
+ export type OutlinedTextFieldProps = CommonTextFieldProperties & {
78
+ /** @default false */
79
+ isError?: boolean;
80
+ /**
81
+ * Shape used for the field's container outline/fill. Use the helpers from
82
+ * `Shape` (for example, `<Shape.Pill />` or `<Shape.RoundedCorner cornerRadii={...} />`).
83
+ * Defaults to the Material `OutlinedTextFieldDefaults.shape`/`TextFieldDefaults.shape`.
84
+ */
85
+ shape?: ShapeJSXElement;
86
+ colors?: TextFieldColors;
87
+ };
88
+
89
+ // endregion Types
90
+
91
+ // region Native
92
+
93
+ type NativeTextFieldProps = Omit<
94
+ TextFieldProps,
95
+ | 'value'
96
+ | 'selection'
97
+ | 'onValueChange'
98
+ | 'onFocusChanged'
99
+ | 'onSelectionChange'
100
+ | 'keyboardActions'
101
+ | 'children'
102
+ | 'shape'
103
+ > &
104
+ CommonNativeTextFieldProps & {
105
+ variant: 'filled' | 'outlined';
106
+ colors?: TextFieldColors;
107
+ shape?: ShapeRecordProps;
108
+ };
109
+
110
+ const TextFieldNativeView: React.ComponentType<NativeTextFieldProps> = requireNativeView(
111
+ 'ExpoUI',
112
+ 'TextFieldView'
113
+ );
114
+
115
+ function useTransformedProps(
116
+ props: TextFieldProps | OutlinedTextFieldProps,
117
+ variant: 'filled' | 'outlined'
118
+ ): NativeTextFieldProps {
119
+ const { shape, ...rest } = props;
120
+ return {
121
+ ...useCommonTextFieldProps(rest),
122
+ variant,
123
+ shape: parseJSXShape(shape),
124
+ };
125
+ }
126
+
127
+ // endregion Native
128
+
129
+ // region Slot components
130
+
131
+ function Label(props: { children: React.ReactNode }) {
132
+ return <Slot slotName="label">{props.children}</Slot>;
133
+ }
134
+
135
+ function Placeholder(props: { children: React.ReactNode }) {
136
+ return <Slot slotName="placeholder">{props.children}</Slot>;
137
+ }
138
+
139
+ function LeadingIcon(props: { children: React.ReactNode }) {
140
+ return <Slot slotName="leadingIcon">{props.children}</Slot>;
141
+ }
142
+
143
+ function TrailingIcon(props: { children: React.ReactNode }) {
144
+ return <Slot slotName="trailingIcon">{props.children}</Slot>;
145
+ }
146
+
147
+ function Prefix(props: { children: React.ReactNode }) {
148
+ return <Slot slotName="prefix">{props.children}</Slot>;
149
+ }
150
+
151
+ function Suffix(props: { children: React.ReactNode }) {
152
+ return <Slot slotName="suffix">{props.children}</Slot>;
153
+ }
154
+
155
+ function SupportingText(props: { children: React.ReactNode }) {
156
+ return <Slot slotName="supportingText">{props.children}</Slot>;
157
+ }
158
+
159
+ // endregion Slot components
160
+
161
+ // region Components
162
+
163
+ /**
164
+ * A Material3 `TextField`.
165
+ */
166
+ function TextFieldComponent(props: TextFieldProps) {
167
+ return <TextFieldNativeView {...useTransformedProps(props, 'filled')} />;
168
+ }
169
+
170
+ TextFieldComponent.Label = Label;
171
+ TextFieldComponent.Placeholder = Placeholder;
172
+ TextFieldComponent.LeadingIcon = LeadingIcon;
173
+ TextFieldComponent.TrailingIcon = TrailingIcon;
174
+ TextFieldComponent.Prefix = Prefix;
175
+ TextFieldComponent.Suffix = Suffix;
176
+ TextFieldComponent.SupportingText = SupportingText;
177
+
178
+ /**
179
+ * A Material3 `OutlinedTextField` with a transparent background and border outline.
180
+ */
181
+ function OutlinedTextFieldComponent(props: OutlinedTextFieldProps) {
182
+ return <TextFieldNativeView {...useTransformedProps(props, 'outlined')} />;
183
+ }
184
+
185
+ OutlinedTextFieldComponent.Label = Label;
186
+ OutlinedTextFieldComponent.Placeholder = Placeholder;
187
+ OutlinedTextFieldComponent.LeadingIcon = LeadingIcon;
188
+ OutlinedTextFieldComponent.TrailingIcon = TrailingIcon;
189
+ OutlinedTextFieldComponent.Prefix = Prefix;
190
+ OutlinedTextFieldComponent.Suffix = Suffix;
191
+ OutlinedTextFieldComponent.SupportingText = SupportingText;
192
+
193
+ // endregion Components
194
+
195
+ export { TextFieldComponent as TextField, OutlinedTextFieldComponent as OutlinedTextField };
196
+
197
+ // Exported for docs api data
198
+ export { type ObservableState };
@@ -0,0 +1,19 @@
1
+ export {
2
+ TextField,
3
+ OutlinedTextField,
4
+ type TextFieldColors,
5
+ type TextFieldProps,
6
+ type OutlinedTextFieldProps,
7
+ type ObservableState,
8
+ } from './TextField';
9
+ export { BasicTextField, type BasicTextFieldProps, type BasicTextFieldRef } from './BasicTextField';
10
+ export type {
11
+ TextFieldRef,
12
+ TextFieldCapitalization,
13
+ TextFieldImeAction,
14
+ TextFieldKeyboardType,
15
+ TextFieldKeyboardOptions,
16
+ TextFieldKeyboardActions,
17
+ TextFieldTextStyle,
18
+ CommonTextFieldProperties,
19
+ } from './shared';