@expo/ui 56.0.16 → 56.0.18

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 (133) hide show
  1. package/CHANGELOG.md +33 -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/ModalBottomSheetView.kt +14 -0
  6. package/android/src/main/java/expo/modules/ui/ModifierRegistry.kt +20 -0
  7. package/android/src/main/java/expo/modules/ui/RNHostView.kt +182 -6
  8. package/android/src/main/java/expo/modules/ui/textfield/BasicTextField.kt +203 -0
  9. package/android/src/main/java/expo/modules/ui/{TextFieldView.kt → textfield/TextField.kt} +34 -248
  10. package/android/src/main/java/expo/modules/ui/textfield/TextFieldShared.kt +299 -0
  11. package/build/State/useNativeState.d.ts +8 -3
  12. package/build/State/useNativeState.d.ts.map +1 -1
  13. package/build/community/bottom-sheet/BottomSheet.android.d.ts.map +1 -1
  14. package/build/community/pager-view/PagerView.android.d.ts.map +1 -1
  15. package/build/jetpack-compose/ModalBottomSheet/index.d.ts +6 -0
  16. package/build/jetpack-compose/ModalBottomSheet/index.d.ts.map +1 -1
  17. package/build/jetpack-compose/RNHostView/index.d.ts +8 -0
  18. package/build/jetpack-compose/RNHostView/index.d.ts.map +1 -1
  19. package/build/jetpack-compose/TextField/BasicTextField.d.ts +36 -0
  20. package/build/jetpack-compose/TextField/BasicTextField.d.ts.map +1 -0
  21. package/build/jetpack-compose/TextField/TextField.d.ts +131 -0
  22. package/build/jetpack-compose/TextField/TextField.d.ts.map +1 -0
  23. package/build/jetpack-compose/TextField/index.d.ts +3 -244
  24. package/build/jetpack-compose/TextField/index.d.ts.map +1 -1
  25. package/build/jetpack-compose/TextField/shared.d.ts +171 -0
  26. package/build/jetpack-compose/TextField/shared.d.ts.map +1 -0
  27. package/build/jetpack-compose/index.d.ts +1 -1
  28. package/build/jetpack-compose/index.d.ts.map +1 -1
  29. package/build/jetpack-compose/modifiers/index.d.ts +11 -0
  30. package/build/jetpack-compose/modifiers/index.d.ts.map +1 -1
  31. package/build/swift-ui/Image/index.d.ts +3 -1
  32. package/build/swift-ui/Image/index.d.ts.map +1 -1
  33. package/build/swift-ui/modifiers/index.d.ts +34 -5
  34. package/build/swift-ui/modifiers/index.d.ts.map +1 -1
  35. package/build/swift-ui/modifiers/widgets.d.ts +7 -0
  36. package/build/swift-ui/modifiers/widgets.d.ts.map +1 -1
  37. package/build/universal/Button/index.ios.d.ts.map +1 -1
  38. package/build/universal/FieldGroup/FieldSectionSlots.d.ts.map +1 -1
  39. package/build/universal/FieldGroup/groupChildren.d.ts.map +1 -1
  40. package/build/universal/Text/index.ios.d.ts.map +1 -1
  41. package/build/universal/TextInput/index.android.d.ts.map +1 -1
  42. package/build/universal/TextInput/types.d.ts +5 -1
  43. package/build/universal/TextInput/types.d.ts.map +1 -1
  44. package/build/universal/modifierUtils.d.ts +16 -0
  45. package/build/universal/modifierUtils.d.ts.map +1 -0
  46. package/build/universal/transformStyle.android.d.ts +3 -0
  47. package/build/universal/transformStyle.android.d.ts.map +1 -1
  48. package/build/universal/transformStyle.ios.d.ts +3 -0
  49. package/build/universal/transformStyle.ios.d.ts.map +1 -1
  50. package/build/universal/types.d.ts +2 -0
  51. package/build/universal/types.d.ts.map +1 -1
  52. package/expo-module.config.json +1 -1
  53. package/ios/ImageView.swift +1 -5
  54. package/ios/Modifiers/ImageScaleModifier.swift +29 -0
  55. package/ios/Modifiers/OnGeometryChangeModifier.swift +8 -16
  56. package/ios/Modifiers/ViewModifierRegistry.swift +36 -0
  57. package/ios/Modifiers/WidgetModifiers.swift +12 -0
  58. package/local-maven-repo/expo/modules/ui/expo.modules.ui/{56.0.16/expo.modules.ui-56.0.16-sources.jar → 56.0.18/expo.modules.ui-56.0.18-sources.jar} +0 -0
  59. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.18/expo.modules.ui-56.0.18-sources.jar.md5 +1 -0
  60. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.18/expo.modules.ui-56.0.18-sources.jar.sha1 +1 -0
  61. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.18/expo.modules.ui-56.0.18-sources.jar.sha256 +1 -0
  62. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.18/expo.modules.ui-56.0.18-sources.jar.sha512 +1 -0
  63. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.18/expo.modules.ui-56.0.18.aar +0 -0
  64. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.18/expo.modules.ui-56.0.18.aar.md5 +1 -0
  65. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.18/expo.modules.ui-56.0.18.aar.sha1 +1 -0
  66. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.18/expo.modules.ui-56.0.18.aar.sha256 +1 -0
  67. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.18/expo.modules.ui-56.0.18.aar.sha512 +1 -0
  68. package/local-maven-repo/expo/modules/ui/expo.modules.ui/{56.0.16/expo.modules.ui-56.0.16.module → 56.0.18/expo.modules.ui-56.0.18.module} +22 -22
  69. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.18/expo.modules.ui-56.0.18.module.md5 +1 -0
  70. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.18/expo.modules.ui-56.0.18.module.sha1 +1 -0
  71. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.18/expo.modules.ui-56.0.18.module.sha256 +1 -0
  72. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.18/expo.modules.ui-56.0.18.module.sha512 +1 -0
  73. package/local-maven-repo/expo/modules/ui/expo.modules.ui/{56.0.16/expo.modules.ui-56.0.16.pom → 56.0.18/expo.modules.ui-56.0.18.pom} +1 -1
  74. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.18/expo.modules.ui-56.0.18.pom.md5 +1 -0
  75. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.18/expo.modules.ui-56.0.18.pom.sha1 +1 -0
  76. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.18/expo.modules.ui-56.0.18.pom.sha256 +1 -0
  77. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.18/expo.modules.ui-56.0.18.pom.sha512 +1 -0
  78. package/local-maven-repo/expo/modules/ui/expo.modules.ui/maven-metadata.xml +4 -4
  79. package/local-maven-repo/expo/modules/ui/expo.modules.ui/maven-metadata.xml.md5 +1 -1
  80. package/local-maven-repo/expo/modules/ui/expo.modules.ui/maven-metadata.xml.sha1 +1 -1
  81. package/local-maven-repo/expo/modules/ui/expo.modules.ui/maven-metadata.xml.sha256 +1 -1
  82. package/local-maven-repo/expo/modules/ui/expo.modules.ui/maven-metadata.xml.sha512 +1 -1
  83. package/package.json +3 -3
  84. package/src/State/index.fx.ts +4 -1
  85. package/src/State/useNativeState.ts +24 -5
  86. package/src/community/bottom-sheet/BottomSheet.android.tsx +2 -13
  87. package/src/community/bottom-sheet/BottomSheet.ios.tsx +1 -1
  88. package/src/community/datetime-picker/DateTimePicker.tsx +1 -1
  89. package/src/community/menu/MenuView.ios.tsx +1 -1
  90. package/src/community/pager-view/PagerView.android.tsx +21 -3
  91. package/src/community/pager-view/PagerView.ios.tsx +1 -1
  92. package/src/community/picker/Picker.ios.tsx +1 -1
  93. package/src/community/slider/Slider.ios.tsx +1 -1
  94. package/src/jetpack-compose/ModalBottomSheet/index.tsx +7 -0
  95. package/src/jetpack-compose/RNHostView/index.tsx +8 -0
  96. package/src/jetpack-compose/TextField/BasicTextField.tsx +118 -0
  97. package/src/jetpack-compose/TextField/TextField.tsx +198 -0
  98. package/src/jetpack-compose/TextField/index.ts +19 -0
  99. package/src/jetpack-compose/TextField/{index.tsx → shared.ts} +71 -203
  100. package/src/jetpack-compose/index.ts +6 -0
  101. package/src/jetpack-compose/modifiers/index.ts +13 -0
  102. package/src/swift-ui/BottomSheet/index.tsx +1 -1
  103. package/src/swift-ui/Image/index.tsx +12 -3
  104. package/src/swift-ui/modifiers/index.ts +44 -6
  105. package/src/swift-ui/modifiers/widgets.ts +9 -0
  106. package/src/universal/Button/index.ios.tsx +6 -1
  107. package/src/universal/FieldGroup/FieldSectionSlots.tsx +3 -0
  108. package/src/universal/FieldGroup/groupChildren.tsx +3 -0
  109. package/src/universal/Text/index.ios.tsx +3 -1
  110. package/src/universal/TextInput/index.android.tsx +26 -60
  111. package/src/universal/TextInput/types.ts +5 -1
  112. package/src/universal/modifierUtils.ts +23 -0
  113. package/src/universal/transformStyle.android.ts +9 -1
  114. package/src/universal/transformStyle.ios.ts +9 -1
  115. package/src/universal/types.ts +2 -0
  116. package/android/src/main/java/expo/modules/ui/ShadowNodeSyncFlush.kt +0 -28
  117. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.16/expo.modules.ui-56.0.16-sources.jar.md5 +0 -1
  118. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.16/expo.modules.ui-56.0.16-sources.jar.sha1 +0 -1
  119. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.16/expo.modules.ui-56.0.16-sources.jar.sha256 +0 -1
  120. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.16/expo.modules.ui-56.0.16-sources.jar.sha512 +0 -1
  121. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.16/expo.modules.ui-56.0.16.aar +0 -0
  122. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.16/expo.modules.ui-56.0.16.aar.md5 +0 -1
  123. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.16/expo.modules.ui-56.0.16.aar.sha1 +0 -1
  124. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.16/expo.modules.ui-56.0.16.aar.sha256 +0 -1
  125. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.16/expo.modules.ui-56.0.16.aar.sha512 +0 -1
  126. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.16/expo.modules.ui-56.0.16.module.md5 +0 -1
  127. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.16/expo.modules.ui-56.0.16.module.sha1 +0 -1
  128. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.16/expo.modules.ui-56.0.16.module.sha256 +0 -1
  129. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.16/expo.modules.ui-56.0.16.module.sha512 +0 -1
  130. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.16/expo.modules.ui-56.0.16.pom.md5 +0 -1
  131. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.16/expo.modules.ui-56.0.16.pom.sha1 +0 -1
  132. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.16/expo.modules.ui-56.0.16.pom.sha256 +0 -1
  133. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.16/expo.modules.ui-56.0.16.pom.sha512 +0 -1
@@ -1,17 +1,13 @@
1
- import { requireNativeView } from 'expo';
2
- import type { Ref } from 'react';
1
+ import type { ReactNode, Ref } from 'react';
3
2
  import type { ColorValue } from 'react-native';
4
3
 
5
4
  import { getStateId, type ObservableState, useWorkletProp, worklets } from '../../State';
6
5
  import type { ModifierConfig, ViewEvent } from '../../types';
7
- import { parseJSXShape, type ShapeJSXElement, type ShapeRecordProps } from '../Shape';
8
- import { Slot } from '../SlotView';
9
6
  import { createViewModifierEventListener } from '../modifiers/utils';
10
7
 
11
- // region Types
12
-
13
8
  /**
14
- * Can be used for imperatively focusing and setting text/selection on the `TextField` component.
9
+ * Can be used for imperatively focusing and setting text/selection on the
10
+ * `TextField`, `OutlinedTextField`, and `BasicTextField` components.
15
11
  */
16
12
  export type TextFieldRef = {
17
13
  setText: (newText: string) => Promise<void>;
@@ -76,56 +72,37 @@ export type TextFieldKeyboardActions = {
76
72
  };
77
73
 
78
74
  /**
79
- * Colors for `TextField` and `OutlinedTextField`.
80
- * Maps to `TextFieldColors` in Compose, shared by both variants.
75
+ * Text styling for a text field's content. Maps to Compose's `TextStyle`.
76
+ * Shared by `TextField`, `OutlinedTextField`, and `BasicTextField`.
81
77
  */
82
- export type TextFieldColors = {
83
- focusedTextColor?: ColorValue;
84
- unfocusedTextColor?: ColorValue;
85
- disabledTextColor?: ColorValue;
86
- errorTextColor?: ColorValue;
87
- focusedContainerColor?: ColorValue;
88
- unfocusedContainerColor?: ColorValue;
89
- disabledContainerColor?: ColorValue;
90
- errorContainerColor?: ColorValue;
91
- cursorColor?: ColorValue;
92
- errorCursorColor?: ColorValue;
93
- focusedIndicatorColor?: ColorValue;
94
- unfocusedIndicatorColor?: ColorValue;
95
- disabledIndicatorColor?: ColorValue;
96
- errorIndicatorColor?: ColorValue;
97
- focusedLeadingIconColor?: ColorValue;
98
- unfocusedLeadingIconColor?: ColorValue;
99
- disabledLeadingIconColor?: ColorValue;
100
- errorLeadingIconColor?: ColorValue;
101
- focusedTrailingIconColor?: ColorValue;
102
- unfocusedTrailingIconColor?: ColorValue;
103
- disabledTrailingIconColor?: ColorValue;
104
- errorTrailingIconColor?: ColorValue;
105
- focusedLabelColor?: ColorValue;
106
- unfocusedLabelColor?: ColorValue;
107
- disabledLabelColor?: ColorValue;
108
- errorLabelColor?: ColorValue;
109
- focusedPlaceholderColor?: ColorValue;
110
- unfocusedPlaceholderColor?: ColorValue;
111
- disabledPlaceholderColor?: ColorValue;
112
- errorPlaceholderColor?: ColorValue;
113
- focusedSupportingTextColor?: ColorValue;
114
- unfocusedSupportingTextColor?: ColorValue;
115
- disabledSupportingTextColor?: ColorValue;
116
- errorSupportingTextColor?: ColorValue;
117
- focusedPrefixColor?: ColorValue;
118
- unfocusedPrefixColor?: ColorValue;
119
- disabledPrefixColor?: ColorValue;
120
- errorPrefixColor?: ColorValue;
121
- focusedSuffixColor?: ColorValue;
122
- unfocusedSuffixColor?: ColorValue;
123
- disabledSuffixColor?: ColorValue;
124
- errorSuffixColor?: ColorValue;
78
+ export type TextFieldTextStyle = {
79
+ textAlign?: 'left' | 'right' | 'center' | 'justify';
80
+ color?: ColorValue;
81
+ fontSize?: number;
82
+ fontFamily?: string;
83
+ fontWeight?:
84
+ | '100'
85
+ | '200'
86
+ | '300'
87
+ | '400'
88
+ | '500'
89
+ | '600'
90
+ | '700'
91
+ | '800'
92
+ | '900'
93
+ | 'normal'
94
+ | 'bold';
95
+ lineHeight?: number;
96
+ letterSpacing?: number;
125
97
  };
126
98
 
127
- /** Shared props between `TextField` and `OutlinedTextField`. */
128
- type BaseTextFieldProps = {
99
+ /**
100
+ * Props shared by every Compose text field variant — `TextField`,
101
+ * `OutlinedTextField`, and `BasicTextField`. The Material variants add their
102
+ * own decoration props (`isError`, `shape`, `colors`, slot children);
103
+ * `BasicTextField` adds `cursorColor`.
104
+ */
105
+ export type CommonTextFieldProperties = {
129
106
  ref?: Ref<TextFieldRef>;
130
107
  /**
131
108
  * An observable state that holds the current text value. Create one with
@@ -140,8 +117,6 @@ type BaseTextFieldProps = {
140
117
  /** @default false */
141
118
  readOnly?: boolean;
142
119
  /** @default false */
143
- isError?: boolean;
144
- /** @default false */
145
120
  singleLine?: boolean;
146
121
  maxLines?: number;
147
122
  minLines?: number;
@@ -151,17 +126,6 @@ type BaseTextFieldProps = {
151
126
  */
152
127
  visualTransformation?: 'password' | 'none';
153
128
 
154
- /**
155
- * Selection-related colors. Maps to Compose's `TextSelectionColors` via
156
- * `LocalTextSelectionColors`. `handleColor` controls the drag handles;
157
- * `backgroundColor` is the highlighted-text background (typically the same
158
- * tint at lower alpha so the underlying text stays readable).
159
- */
160
- textSelectionColors?: {
161
- handleColor?: ColorValue;
162
- backgroundColor?: ColorValue;
163
- };
164
-
165
129
  /**
166
130
  * Observable state holding the current selection range. Create with
167
131
  * `useNativeState({ start: 0, end: 0 })`. The field writes user-driven
@@ -178,28 +142,21 @@ type BaseTextFieldProps = {
178
142
  onSelectionChange?: (selection: { start: number; end: number }) => void;
179
143
 
180
144
  /**
181
- * Text styling for the field's content. Maps to Compose's `TextStyle`.
145
+ * Selection-related colors. Maps to Compose's `TextSelectionColors` via
146
+ * `LocalTextSelectionColors`. `handleColor` controls the drag handles (and
147
+ * the caret's drag handle); `backgroundColor` is the highlighted-text
148
+ * background (typically the same tint at lower alpha so the underlying text
149
+ * stays readable). Independent of `cursorColor`, which tints the caret line.
182
150
  */
183
- textStyle?: {
184
- textAlign?: 'left' | 'right' | 'center' | 'justify';
185
- color?: ColorValue;
186
- fontSize?: number;
187
- fontFamily?: string;
188
- fontWeight?:
189
- | '100'
190
- | '200'
191
- | '300'
192
- | '400'
193
- | '500'
194
- | '600'
195
- | '700'
196
- | '800'
197
- | '900'
198
- | 'normal'
199
- | 'bold';
200
- lineHeight?: number;
201
- letterSpacing?: number;
151
+ textSelectionColors?: {
152
+ handleColor?: ColorValue;
153
+ backgroundColor?: ColorValue;
202
154
  };
155
+
156
+ /**
157
+ * Text styling for the field's content. Maps to Compose's `TextStyle`.
158
+ */
159
+ textStyle?: TextFieldTextStyle;
203
160
  keyboardOptions?: TextFieldKeyboardOptions;
204
161
  keyboardActions?: TextFieldKeyboardActions;
205
162
  /**
@@ -211,44 +168,35 @@ type BaseTextFieldProps = {
211
168
  onValueChange?: (value: string) => void;
212
169
  /** A callback triggered when the field gains or loses focus. */
213
170
  onFocusChanged?: (focused: boolean) => void;
214
- /**
215
- * Shape used for the field's container outline/fill. Use the helpers from
216
- * `Shape` (for example, `<Shape.Pill />` or `<Shape.RoundedCorner cornerRadii={...} />`).
217
- * Defaults to the Material `OutlinedTextFieldDefaults.shape`/`TextFieldDefaults.shape`.
218
- */
219
- shape?: ShapeJSXElement;
220
171
  modifiers?: ModifierConfig[];
221
- /** Slot children (e.g. `TextField.Label`, `TextField.Placeholder`). */
222
- children?: React.ReactNode;
223
- };
224
-
225
- export type TextFieldProps = BaseTextFieldProps & {
226
- colors?: TextFieldColors;
227
- };
228
-
229
- export type OutlinedTextFieldProps = BaseTextFieldProps & {
230
- colors?: TextFieldColors;
172
+ /** Slot children that configure the field's decoration. */
173
+ children?: ReactNode;
231
174
  };
232
175
 
233
- // endregion Types
176
+ // region Native transform
234
177
 
235
- // region Native
236
-
237
- type NativeTextFieldProps = Omit<
238
- BaseTextFieldProps,
178
+ /**
179
+ * Keys consumed (and reshaped) by {@link useCommonTextFieldProps}. Everything
180
+ * else on the props passes through untouched.
181
+ */
182
+ type TransformedKeys =
239
183
  | 'value'
240
184
  | 'selection'
185
+ | 'modifiers'
186
+ | 'children'
187
+ | 'keyboardActions'
241
188
  | 'onValueChange'
242
189
  | 'onFocusChanged'
243
- | 'onSelectionChange'
244
- | 'keyboardActions'
245
- | 'children'
246
- | 'shape'
247
- > & {
248
- variant: 'filled' | 'outlined';
249
- colors?: TextFieldColors;
250
- shape?: ShapeRecordProps;
251
- children?: React.ReactNode;
190
+ | 'onSelectionChange';
191
+
192
+ /**
193
+ * Native-facing prop shape shared by every Compose text field variant. The
194
+ * observable-backed props collapse to shared-object ids, and the public
195
+ * callbacks become `nativeEvent`-wrapped listeners.
196
+ */
197
+ export type CommonNativeTextFieldProps = {
198
+ modifiers?: ModifierConfig[];
199
+ children?: ReactNode;
252
200
  value?: number | null;
253
201
  selection?: number | null;
254
202
  onValueChangeSync?: number | null;
@@ -257,15 +205,9 @@ type NativeTextFieldProps = Omit<
257
205
  ViewEvent<'onSelectionChange', { start: number; end: number }> &
258
206
  ViewEvent<'onKeyboardAction', { action: string; value: string }>;
259
207
 
260
- const TextFieldNativeView: React.ComponentType<NativeTextFieldProps> = requireNativeView(
261
- 'ExpoUI',
262
- 'TextFieldView'
263
- );
264
-
265
- function useTransformedProps(
266
- props: TextFieldProps | OutlinedTextFieldProps,
267
- variant: 'filled' | 'outlined'
268
- ): NativeTextFieldProps {
208
+ export function useCommonTextFieldProps<T extends CommonTextFieldProperties>(
209
+ props: T
210
+ ): CommonNativeTextFieldProps & Omit<T, TransformedKeys> {
269
211
  const {
270
212
  value,
271
213
  selection,
@@ -275,19 +217,16 @@ function useTransformedProps(
275
217
  onValueChange,
276
218
  onFocusChanged,
277
219
  onSelectionChange,
278
- shape,
279
- ...restProps
220
+ ...rest
280
221
  } = props;
281
222
 
282
223
  const isWorklet = !!onValueChange && !!worklets?.isWorkletFunction?.(onValueChange);
283
224
  const workletCallback = useWorkletProp(isWorklet ? onValueChange : undefined, 'onValueChange');
284
225
 
285
226
  return {
227
+ ...rest,
286
228
  modifiers,
287
229
  ...(modifiers ? createViewModifierEventListener(modifiers) : undefined),
288
- ...restProps,
289
- variant,
290
- shape: parseJSXShape(shape),
291
230
  children,
292
231
  value: getStateId(value),
293
232
  selection: getStateId(selection),
@@ -315,75 +254,4 @@ function useTransformedProps(
315
254
  };
316
255
  }
317
256
 
318
- // endregion Native
319
-
320
- // region Slot components
321
-
322
- function Label(props: { children: React.ReactNode }) {
323
- return <Slot slotName="label">{props.children}</Slot>;
324
- }
325
-
326
- function Placeholder(props: { children: React.ReactNode }) {
327
- return <Slot slotName="placeholder">{props.children}</Slot>;
328
- }
329
-
330
- function LeadingIcon(props: { children: React.ReactNode }) {
331
- return <Slot slotName="leadingIcon">{props.children}</Slot>;
332
- }
333
-
334
- function TrailingIcon(props: { children: React.ReactNode }) {
335
- return <Slot slotName="trailingIcon">{props.children}</Slot>;
336
- }
337
-
338
- function Prefix(props: { children: React.ReactNode }) {
339
- return <Slot slotName="prefix">{props.children}</Slot>;
340
- }
341
-
342
- function Suffix(props: { children: React.ReactNode }) {
343
- return <Slot slotName="suffix">{props.children}</Slot>;
344
- }
345
-
346
- function SupportingText(props: { children: React.ReactNode }) {
347
- return <Slot slotName="supportingText">{props.children}</Slot>;
348
- }
349
-
350
- // endregion Slot components
351
-
352
- // region Components
353
-
354
- /**
355
- * A Material3 `TextField`.
356
- */
357
- function TextFieldComponent(props: TextFieldProps) {
358
- return <TextFieldNativeView {...useTransformedProps(props, 'filled')} />;
359
- }
360
-
361
- TextFieldComponent.Label = Label;
362
- TextFieldComponent.Placeholder = Placeholder;
363
- TextFieldComponent.LeadingIcon = LeadingIcon;
364
- TextFieldComponent.TrailingIcon = TrailingIcon;
365
- TextFieldComponent.Prefix = Prefix;
366
- TextFieldComponent.Suffix = Suffix;
367
- TextFieldComponent.SupportingText = SupportingText;
368
-
369
- /**
370
- * A Material3 `OutlinedTextField` with a transparent background and border outline.
371
- */
372
- function OutlinedTextFieldComponent(props: OutlinedTextFieldProps) {
373
- return <TextFieldNativeView {...useTransformedProps(props, 'outlined')} />;
374
- }
375
-
376
- OutlinedTextFieldComponent.Label = Label;
377
- OutlinedTextFieldComponent.Placeholder = Placeholder;
378
- OutlinedTextFieldComponent.LeadingIcon = LeadingIcon;
379
- OutlinedTextFieldComponent.TrailingIcon = TrailingIcon;
380
- OutlinedTextFieldComponent.Prefix = Prefix;
381
- OutlinedTextFieldComponent.Suffix = Suffix;
382
- OutlinedTextFieldComponent.SupportingText = SupportingText;
383
-
384
- // endregion Components
385
-
386
- export { TextFieldComponent as TextField, OutlinedTextFieldComponent as OutlinedTextField };
387
-
388
- // Exported for docs api data
389
- export { type ObservableState };
257
+ // endregion Native transform
@@ -29,7 +29,11 @@ export * from './SyncSwitch';
29
29
  export {
30
30
  TextField,
31
31
  OutlinedTextField,
32
+ BasicTextField,
32
33
  type TextFieldProps,
34
+ type OutlinedTextFieldProps,
35
+ type BasicTextFieldProps,
36
+ type BasicTextFieldRef,
33
37
  type TextFieldRef,
34
38
  type TextFieldCapitalization,
35
39
  type TextFieldImeAction,
@@ -37,6 +41,8 @@ export {
37
41
  type TextFieldKeyboardType,
38
42
  type TextFieldKeyboardActions,
39
43
  type TextFieldColors,
44
+ type TextFieldTextStyle,
45
+ type CommonTextFieldProperties,
40
46
  } from './TextField';
41
47
  export * from './ToggleButton';
42
48
  export * from './Shape';
@@ -420,6 +420,19 @@ export const onSizeChanged = (handler: (size: { width: number; height: number })
420
420
  handler(size)
421
421
  );
422
422
 
423
+ /**
424
+ * Calls the handler whenever the composable is positioned, with its position and size.
425
+ * `x` and `y` are relative to the window. All values are in dp.
426
+ * @param handler - Function called with the new layout.
427
+ */
428
+ export const onGloballyPositioned = (
429
+ handler: (layout: { x: number; y: number; width: number; height: number }) => void
430
+ ) =>
431
+ createModifierWithEventListener(
432
+ 'onGloballyPositioned',
433
+ (layout: { x: number; y: number; width: number; height: number }) => handler(layout)
434
+ );
435
+
423
436
  // =============================================================================
424
437
  // Utility Modifiers
425
438
  // =============================================================================
@@ -1,6 +1,6 @@
1
1
  import { requireNativeView } from 'expo';
2
2
  import { useState, type ComponentType } from 'react';
3
- import type { NativeSyntheticEvent } from 'react-native';
3
+ import { type NativeSyntheticEvent } from 'react-native';
4
4
 
5
5
  import { createViewModifierEventListener } from '../modifiers/utils';
6
6
  import { type CommonViewModifierProps } from '../types';
@@ -3,6 +3,7 @@ import type { ColorValue } from 'react-native';
3
3
  import type { SFSymbol } from 'sf-symbols-typescript';
4
4
 
5
5
  import type { ViewEvent } from '../../types';
6
+ import { font, foregroundStyle } from '../modifiers';
6
7
  import { createViewModifierEventListener } from '../modifiers/utils';
7
8
  import type { CommonViewModifierProps } from '../types';
8
9
 
@@ -23,7 +24,9 @@ export interface ImageProps extends CommonViewModifierProps {
23
24
  */
24
25
  uiImage?: string;
25
26
  /**
26
- * The size of the system image.
27
+ * The fixed size of the system image in points. Does not scale with Dynamic
28
+ * Type. Use the `font` modifier with `textStyle` for that. Ignored when a
29
+ * `font` modifier is supplied.
27
30
  */
28
31
  size?: number;
29
32
  /**
@@ -53,9 +56,15 @@ type TapEvent = ViewEvent<'onTap', object> & {
53
56
  type NativeImageProps = Omit<ImageProps, 'onPress'> | TapEvent;
54
57
 
55
58
  function transformNativeProps(props: ImageProps): NativeImageProps {
56
- const { onPress, modifiers, ...restProps } = props;
59
+ const { onPress, modifiers, size, color, ...restProps } = props;
60
+ const hasFontModifier = modifiers?.some((modifier) => modifier.$type === 'font');
61
+ const allModifiers = [
62
+ ...(modifiers ?? []),
63
+ ...(hasFontModifier ? [] : [font({ size: size ?? 24 })]),
64
+ ...(color != null ? [foregroundStyle(color)] : []),
65
+ ];
57
66
  return {
58
- modifiers,
67
+ modifiers: allModifiers,
59
68
  ...(modifiers ? createViewModifierEventListener(modifiers) : undefined),
60
69
  ...restProps,
61
70
  ...(onPress ? { useTapGesture: true, onTap: () => onPress() } : null),
@@ -23,7 +23,7 @@ import { onScrollPhaseChange, useScrollGeometryChange } from './scrollObservatio
23
23
  import { id, scrollPosition } from './scrollPosition';
24
24
  import { symbolEffect } from './symbolEffect';
25
25
  import type { Color } from './types';
26
- import { widgetAccentedRenderingMode, widgetURL } from './widgets';
26
+ import { activityBackgroundTint, widgetAccentedRenderingMode, widgetURL } from './widgets';
27
27
 
28
28
  const ExpoUI = requireNativeModule('ExpoUI');
29
29
 
@@ -190,13 +190,17 @@ export const onDisappear = (handler: () => void) =>
190
190
  createModifierWithEventListener('onDisappear', handler);
191
191
 
192
192
  /**
193
- * Calls the handler whenever the view's geometry changes. Sizes are in points.
194
- * @param handler - Function called with the new size.
193
+ * Calls the handler whenever the view's geometry changes, with its position and size.
194
+ * `x` and `y` are in the global coordinate space (relative to the window); all values are in points.
195
+ * @param handler - Function called with the new frame.
195
196
  * @see Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/ongeometrychange(for:of:action:)).
196
197
  */
197
- export const onGeometryChange = (handler: (size: { width: number; height: number }) => void) =>
198
- createModifierWithEventListener('onGeometryChange', (size: { width: number; height: number }) =>
199
- handler(size)
198
+ export const onGeometryChange = (
199
+ handler: (frame: { x: number; y: number; width: number; height: number }) => void
200
+ ) =>
201
+ createModifierWithEventListener(
202
+ 'onGeometryChange',
203
+ (frame: { x: number; y: number; width: number; height: number }) => handler(frame)
200
204
  );
201
205
 
202
206
  /**
@@ -561,6 +565,14 @@ export const toggleStyle = (style: 'automatic' | 'switch' | 'button') =>
561
565
  export const controlSize = (size: 'mini' | 'small' | 'regular' | 'large' | 'extraLarge') =>
562
566
  createModifier('controlSize', { size });
563
567
 
568
+ /**
569
+ * Scales SF Symbols within this view relative to the surrounding text, using one of the standard sizes.
570
+ * @param scale - The relative image scale.
571
+ * @see Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/imagescale(_:)).
572
+ */
573
+ export const imageScale = (scale: 'small' | 'medium' | 'large') =>
574
+ createModifier('imageScale', { scale });
575
+
564
576
  /**
565
577
  * Sets the style for labels within this view.
566
578
  * @param style - The label style.
@@ -731,6 +743,16 @@ export const accessibilityHint = (hint: string) => createModifier('accessibility
731
743
  export const accessibilityValue = (value: string) =>
732
744
  createModifier('accessibilityValue', { value });
733
745
 
746
+ /**
747
+ * Sets alternative spoken phrases that Voice Control uses to refer to the view.
748
+ * Each label is read as a `Text` element on iOS. For example, an "End" button
749
+ * might offer "Hang up" so users can trigger it by saying that phrase.
750
+ * @param inputLabels - The spoken phrases that select the view.
751
+ * @see Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/accessibilityinputlabels(_:)).
752
+ */
753
+ export const accessibilityInputLabels = (inputLabels: string[]) =>
754
+ createModifier('accessibilityInputLabels', { inputLabels });
755
+
734
756
  /**
735
757
  * Sets an accessibility identifier for the view.
736
758
  *
@@ -893,6 +915,19 @@ export const truncationMode = (mode: 'head' | 'middle' | 'tail') =>
893
915
  * @see Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/allowstightening(_:)).
894
916
  */
895
917
  export const allowsTightening = (value: boolean) => createModifier('allowsTightening', { value });
918
+ /**
919
+ * Sets the minimum amount that text in this view scales down to fit in the available space.
920
+ *
921
+ * Use this modifier if the text you place in a view doesn't fit and it's okay if the text shrinks
922
+ * to accommodate. For example, a label with a minimum scale factor of `0.5` draws its text in a
923
+ * font size as small as half of the actual font if needed.
924
+ * @param factor - A fraction between `0` and `1` (including `0` and `1`) that specifies the amount
925
+ * of text to draw. For example, a value of `0.5` draws the text in a font size as small as half the
926
+ * actual font if needed.
927
+ * @see Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/minimumscalefactor(_:)).
928
+ */
929
+ export const minimumScaleFactor = (factor: number) =>
930
+ createModifier('minimumScaleFactor', { factor });
896
931
  /**
897
932
  * Sets the spacing, or kerning, between characters for the text in this view.
898
933
  * @default 0
@@ -1428,6 +1463,7 @@ export type BuiltInModifier =
1428
1463
  | ReturnType<typeof buttonBorderShape>
1429
1464
  | ReturnType<typeof toggleStyle>
1430
1465
  | ReturnType<typeof controlSize>
1466
+ | ReturnType<typeof imageScale>
1431
1467
  | ReturnType<typeof labelStyle>
1432
1468
  | ReturnType<typeof labelsHidden>
1433
1469
  | ReturnType<typeof textFieldStyle>
@@ -1435,6 +1471,7 @@ export type BuiltInModifier =
1435
1471
  | ReturnType<typeof accessibilityLabel>
1436
1472
  | ReturnType<typeof accessibilityHint>
1437
1473
  | ReturnType<typeof accessibilityValue>
1474
+ | ReturnType<typeof accessibilityInputLabels>
1438
1475
  | ReturnType<typeof accessibilityIdentifier>
1439
1476
  | ReturnType<typeof accessibilityHidden>
1440
1477
  | ReturnType<typeof layoutPriority>
@@ -1503,6 +1540,7 @@ export type BuiltInModifier =
1503
1540
  | ReturnType<typeof symbolEffect>
1504
1541
  | ReturnType<typeof widgetAccentedRenderingMode>
1505
1542
  | ReturnType<typeof widgetURL>
1543
+ | ReturnType<typeof activityBackgroundTint>
1506
1544
  | ReturnType<typeof containerBackground>;
1507
1545
 
1508
1546
  /**
@@ -1,4 +1,5 @@
1
1
  import { createModifier } from './createModifier';
2
+ import type { Color } from './types';
2
3
 
3
4
  /**
4
5
  * Specifies the how to render an Image when using the WidgetKit/WidgetRenderingMode/accented mode.
@@ -16,3 +17,11 @@ export const widgetAccentedRenderingMode = (
16
17
  * @see Official [SwiftUI documentation](https://developer.apple.com/documentation/SwiftUI/View/widgetURL(_:)).
17
18
  */
18
19
  export const widgetURL = (url: string) => createModifier('widgetURL', { url });
20
+
21
+ /**
22
+ * Sets the background tint color for a Live Activity.
23
+ * @param color - The background tint color, or `null` to use the system default.
24
+ * @see Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/activitybackgroundtint(_:)).
25
+ */
26
+ export const activityBackgroundTint = (color: Color | null) =>
27
+ createModifier('activityBackgroundTint', { color });
@@ -2,6 +2,7 @@ import { Button as SwiftUIButton } from '@expo/ui/swift-ui';
2
2
  import { buttonStyle } from '@expo/ui/swift-ui/modifiers';
3
3
  import type { ModifierConfig } from '@expo/ui/swift-ui/modifiers';
4
4
 
5
+ import { omitUserOverridden } from '../modifierUtils';
5
6
  import { transformToModifiers } from '../transformStyle';
6
7
  import type { ButtonProps, ButtonVariant } from './types';
7
8
 
@@ -24,7 +25,11 @@ export function Button({
24
25
  testID,
25
26
  modifiers: extraModifiers,
26
27
  }: ButtonProps) {
27
- const buttonSpecificModifiers: ModifierConfig[] = [buttonStyle(variantButtonStyle[variant])];
28
+ // A user-supplied buttonStyle modifier replaces the variant's.
29
+ const buttonSpecificModifiers: ModifierConfig[] = omitUserOverridden(
30
+ [buttonStyle(variantButtonStyle[variant])],
31
+ extraModifiers
32
+ );
28
33
 
29
34
  const universalModifiers = transformToModifiers(
30
35
  style,
@@ -44,6 +44,9 @@ export function extractFieldSectionSlots(children: ReactNode): ExtractedFieldSec
44
44
 
45
45
  const walk = (node: ReactNode) => {
46
46
  Children.forEach(node, (child) => {
47
+ if (child == null || typeof child === 'boolean') {
48
+ return;
49
+ }
47
50
  if (!isValidElement(child)) {
48
51
  rows.push(child);
49
52
  return;
@@ -21,6 +21,9 @@ export function groupFieldGroupChildren(children: ReactNode): ReactNode[] {
21
21
  };
22
22
 
23
23
  Children.forEach(children, (child) => {
24
+ if (child == null || typeof child === 'boolean') {
25
+ return;
26
+ }
24
27
  if (isSectionElement(child)) {
25
28
  flush();
26
29
  result.push(child);
@@ -9,6 +9,7 @@ import {
9
9
  } from '@expo/ui/swift-ui/modifiers';
10
10
  import type { ModifierConfig } from '@expo/ui/swift-ui/modifiers';
11
11
 
12
+ import { omitUserOverridden } from '../modifierUtils';
12
13
  import { transformToModifiers } from '../transformStyle';
13
14
  import type { TextProps, UniversalFontWeight } from './types';
14
15
 
@@ -98,7 +99,8 @@ export function Text({
98
99
  extraModifiers
99
100
  );
100
101
 
101
- const modifiers = [...textModifiers, ...universalModifiers];
102
+ // A user-supplied modifier replaces any text-derived modifier of the same type.
103
+ const modifiers = [...omitUserOverridden(textModifiers, extraModifiers), ...universalModifiers];
102
104
 
103
105
  return (
104
106
  <SwiftUIText modifiers={modifiers} testID={testID}>