@expo/ui 56.0.1 → 56.0.3

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 (108) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/android/build.gradle +2 -2
  3. package/android/src/main/java/expo/modules/ui/ExpoUIModule.kt +7 -1
  4. package/android/src/main/java/expo/modules/ui/MaskView.kt +56 -0
  5. package/android/src/main/java/expo/modules/ui/TextFieldView.kt +27 -80
  6. package/android/src/main/java/expo/modules/ui/icon/IconView.kt +6 -1
  7. package/build/community/bottom-sheet/BottomSheet.android.d.ts.map +1 -1
  8. package/build/community/bottom-sheet/BottomSheet.ios.d.ts.map +1 -1
  9. package/build/community/masked-view/MaskedView.android.d.ts +8 -0
  10. package/build/community/masked-view/MaskedView.android.d.ts.map +1 -0
  11. package/build/community/masked-view/MaskedView.d.ts +10 -0
  12. package/build/community/masked-view/MaskedView.d.ts.map +1 -0
  13. package/build/community/masked-view/MaskedView.ios.d.ts +8 -0
  14. package/build/community/masked-view/MaskedView.ios.d.ts.map +1 -0
  15. package/build/community/masked-view/index.d.ts +4 -0
  16. package/build/community/masked-view/index.d.ts.map +1 -0
  17. package/build/community/masked-view/types.d.ts +19 -0
  18. package/build/community/masked-view/types.d.ts.map +1 -0
  19. package/build/community/picker/Picker.android.d.ts +10 -2
  20. package/build/community/picker/Picker.android.d.ts.map +1 -1
  21. package/build/community/picker/Picker.d.ts +10 -2
  22. package/build/community/picker/Picker.d.ts.map +1 -1
  23. package/build/community/picker/Picker.ios.d.ts +10 -2
  24. package/build/community/picker/Picker.ios.d.ts.map +1 -1
  25. package/build/community/picker/types.d.ts +12 -10
  26. package/build/community/picker/types.d.ts.map +1 -1
  27. package/build/jetpack-compose/DropdownMenu/DropdownMenuItem.d.ts +4 -0
  28. package/build/jetpack-compose/DropdownMenu/DropdownMenuItem.d.ts.map +1 -1
  29. package/build/jetpack-compose/HorizontalFloatingToolbar/index.d.ts +8 -0
  30. package/build/jetpack-compose/HorizontalFloatingToolbar/index.d.ts.map +1 -1
  31. package/build/jetpack-compose/HorizontalPager/index.d.ts +2 -1
  32. package/build/jetpack-compose/HorizontalPager/index.d.ts.map +1 -1
  33. package/build/jetpack-compose/Icon/index.d.ts +12 -4
  34. package/build/jetpack-compose/Icon/index.d.ts.map +1 -1
  35. package/build/jetpack-compose/TextField/index.d.ts +21 -34
  36. package/build/jetpack-compose/TextField/index.d.ts.map +1 -1
  37. package/build/jetpack-compose/index.d.ts +2 -2
  38. package/build/jetpack-compose/index.d.ts.map +1 -1
  39. package/build/jetpack-compose/modifiers/index.d.ts +1 -1
  40. package/build/swift-ui/TextField/index.d.ts +1 -0
  41. package/build/swift-ui/TextField/index.d.ts.map +1 -1
  42. package/build/swift-ui/index.d.ts +1 -1
  43. package/build/swift-ui/index.d.ts.map +1 -1
  44. package/expo-module.config.json +1 -1
  45. package/ios/TextFieldView.swift +15 -15
  46. package/local-maven-repo/expo/modules/ui/expo.modules.ui/{56.0.1/expo.modules.ui-56.0.1-sources.jar → 56.0.3/expo.modules.ui-56.0.3-sources.jar} +0 -0
  47. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.3/expo.modules.ui-56.0.3-sources.jar.md5 +1 -0
  48. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.3/expo.modules.ui-56.0.3-sources.jar.sha1 +1 -0
  49. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.3/expo.modules.ui-56.0.3-sources.jar.sha256 +1 -0
  50. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.3/expo.modules.ui-56.0.3-sources.jar.sha512 +1 -0
  51. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.3/expo.modules.ui-56.0.3.aar +0 -0
  52. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.3/expo.modules.ui-56.0.3.aar.md5 +1 -0
  53. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.3/expo.modules.ui-56.0.3.aar.sha1 +1 -0
  54. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.3/expo.modules.ui-56.0.3.aar.sha256 +1 -0
  55. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.3/expo.modules.ui-56.0.3.aar.sha512 +1 -0
  56. package/local-maven-repo/expo/modules/ui/expo.modules.ui/{56.0.1/expo.modules.ui-56.0.1.module → 56.0.3/expo.modules.ui-56.0.3.module} +23 -23
  57. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.3/expo.modules.ui-56.0.3.module.md5 +1 -0
  58. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.3/expo.modules.ui-56.0.3.module.sha1 +1 -0
  59. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.3/expo.modules.ui-56.0.3.module.sha256 +1 -0
  60. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.3/expo.modules.ui-56.0.3.module.sha512 +1 -0
  61. package/local-maven-repo/expo/modules/ui/expo.modules.ui/{56.0.1/expo.modules.ui-56.0.1.pom → 56.0.3/expo.modules.ui-56.0.3.pom} +2 -2
  62. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.3/expo.modules.ui-56.0.3.pom.md5 +1 -0
  63. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.3/expo.modules.ui-56.0.3.pom.sha1 +1 -0
  64. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.3/expo.modules.ui-56.0.3.pom.sha256 +1 -0
  65. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.3/expo.modules.ui-56.0.3.pom.sha512 +1 -0
  66. package/local-maven-repo/expo/modules/ui/expo.modules.ui/maven-metadata.xml +4 -4
  67. package/local-maven-repo/expo/modules/ui/expo.modules.ui/maven-metadata.xml.md5 +1 -1
  68. package/local-maven-repo/expo/modules/ui/expo.modules.ui/maven-metadata.xml.sha1 +1 -1
  69. package/local-maven-repo/expo/modules/ui/expo.modules.ui/maven-metadata.xml.sha256 +1 -1
  70. package/local-maven-repo/expo/modules/ui/expo.modules.ui/maven-metadata.xml.sha512 +1 -1
  71. package/package.json +18 -14
  72. package/src/community/bottom-sheet/BottomSheet.android.tsx +3 -2
  73. package/src/community/bottom-sheet/BottomSheet.ios.tsx +3 -2
  74. package/src/community/masked-view/MaskedView.android.tsx +40 -0
  75. package/src/community/masked-view/MaskedView.ios.tsx +32 -0
  76. package/src/community/masked-view/MaskedView.tsx +34 -0
  77. package/src/community/masked-view/index.tsx +3 -0
  78. package/src/community/masked-view/types.ts +19 -0
  79. package/src/community/picker/Picker.android.tsx +12 -5
  80. package/src/community/picker/Picker.ios.tsx +9 -6
  81. package/src/community/picker/Picker.tsx +3 -4
  82. package/src/community/picker/types.tsx +24 -18
  83. package/src/jetpack-compose/DropdownMenu/DropdownMenuItem.tsx +4 -6
  84. package/src/jetpack-compose/HorizontalFloatingToolbar/index.tsx +8 -8
  85. package/src/jetpack-compose/HorizontalPager/index.tsx +3 -1
  86. package/src/jetpack-compose/Icon/index.tsx +18 -5
  87. package/src/jetpack-compose/TextField/index.tsx +30 -50
  88. package/src/jetpack-compose/index.ts +17 -2
  89. package/src/jetpack-compose/modifiers/index.ts +1 -1
  90. package/src/swift-ui/TextField/index.tsx +3 -0
  91. package/src/swift-ui/index.tsx +6 -1
  92. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.1/expo.modules.ui-56.0.1-sources.jar.md5 +0 -1
  93. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.1/expo.modules.ui-56.0.1-sources.jar.sha1 +0 -1
  94. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.1/expo.modules.ui-56.0.1-sources.jar.sha256 +0 -1
  95. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.1/expo.modules.ui-56.0.1-sources.jar.sha512 +0 -1
  96. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.1/expo.modules.ui-56.0.1.aar +0 -0
  97. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.1/expo.modules.ui-56.0.1.aar.md5 +0 -1
  98. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.1/expo.modules.ui-56.0.1.aar.sha1 +0 -1
  99. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.1/expo.modules.ui-56.0.1.aar.sha256 +0 -1
  100. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.1/expo.modules.ui-56.0.1.aar.sha512 +0 -1
  101. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.1/expo.modules.ui-56.0.1.module.md5 +0 -1
  102. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.1/expo.modules.ui-56.0.1.module.sha1 +0 -1
  103. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.1/expo.modules.ui-56.0.1.module.sha256 +0 -1
  104. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.1/expo.modules.ui-56.0.1.module.sha512 +0 -1
  105. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.1/expo.modules.ui-56.0.1.pom.md5 +0 -1
  106. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.1/expo.modules.ui-56.0.1.pom.sha1 +0 -1
  107. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.1/expo.modules.ui-56.0.1.pom.sha256 +0 -1
  108. package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.1/expo.modules.ui-56.0.1.pom.sha512 +0 -1
@@ -1,5 +1,5 @@
1
1
  import { useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState } from 'react';
2
- import { View } from 'react-native';
2
+ import { useWindowDimensions, View } from 'react-native';
3
3
 
4
4
  import { BottomSheetContext, BottomSheetInternalContext } from './context';
5
5
  import type { BottomSheetMethods, BottomSheetProps } from './types';
@@ -82,6 +82,7 @@ export function BottomSheet(props: BottomSheetProps) {
82
82
  handleComponent,
83
83
  children,
84
84
  } = props;
85
+ const { width } = useWindowDimensions();
85
86
 
86
87
  // Two-state pattern for animated close:
87
88
  // - isMounted: whether the native sheet tree exists in the React tree
@@ -234,7 +235,7 @@ export function BottomSheet(props: BottomSheetProps) {
234
235
  return (
235
236
  <BottomSheetInternalContext.Provider value={internalContextValue}>
236
237
  <BottomSheetContext.Provider value={methods}>
237
- <Host matchContents>
238
+ <Host style={{ position: 'absolute', width }}>
238
239
  <NativeBottomSheet
239
240
  isPresented={isPresented}
240
241
  onIsPresentedChange={handlePresentedChange}
@@ -0,0 +1,40 @@
1
+ import { requireNativeView } from 'expo';
2
+ import { StyleSheet, View } from 'react-native';
3
+
4
+ import type { MaskedViewProps } from './types';
5
+ import { Host } from '../../jetpack-compose/Host';
6
+ import { RNHostView } from '../../jetpack-compose/RNHostView';
7
+ import { Slot } from '../../jetpack-compose/SlotView';
8
+ import { fillMaxSize } from '../../jetpack-compose/modifiers';
9
+
10
+ const MaskNativeView: React.ComponentType<{
11
+ alignment?: 'topStart';
12
+ modifiers?: ReturnType<typeof fillMaxSize>[];
13
+ children?: React.ReactNode;
14
+ }> = requireNativeView('ExpoUI', 'MaskView');
15
+
16
+ /**
17
+ * Android implementation of `MaskedView`. Bridges arbitrary React Native children
18
+ * (and `maskElement`) into the Compose `MaskView` primitive via `RNHostView`.
19
+ */
20
+ export function MaskedView(props: MaskedViewProps) {
21
+ const { maskElement, children, style, ...viewProps } = props;
22
+ return (
23
+ <View {...viewProps} style={style}>
24
+ <Host style={StyleSheet.absoluteFill}>
25
+ <MaskNativeView alignment="topStart" modifiers={[fillMaxSize()]}>
26
+ <RNHostView modifiers={[fillMaxSize()]}>
27
+ <View style={[StyleSheet.absoluteFill, style]}>{children}</View>
28
+ </RNHostView>
29
+ <Slot slotName="content">
30
+ <RNHostView modifiers={[fillMaxSize()]}>
31
+ <View style={[StyleSheet.absoluteFill, style]}>{maskElement}</View>
32
+ </RNHostView>
33
+ </Slot>
34
+ </MaskNativeView>
35
+ </Host>
36
+ </View>
37
+ );
38
+ }
39
+
40
+ export default MaskedView;
@@ -0,0 +1,32 @@
1
+ import { StyleSheet, View } from 'react-native';
2
+
3
+ import type { MaskedViewProps } from './types';
4
+ import { Host } from '../../swift-ui/Host';
5
+ import { Mask } from '../../swift-ui/Mask';
6
+ import { RNHostView } from '../../swift-ui/RNHostView';
7
+
8
+ /**
9
+ * iOS implementation of `MaskedView`. Bridges arbitrary React Native children
10
+ * (and `maskElement`) into the SwiftUI `Mask` primitive via `RNHostView`.
11
+ */
12
+ export function MaskedView(props: MaskedViewProps) {
13
+ const { maskElement, children, style, ...viewProps } = props;
14
+ return (
15
+ <View {...viewProps} style={style}>
16
+ <Host style={StyleSheet.absoluteFill}>
17
+ <Mask alignment="topLeading">
18
+ <RNHostView>
19
+ <View style={[StyleSheet.absoluteFill, style]}>{children}</View>
20
+ </RNHostView>
21
+ <Mask.Content>
22
+ <RNHostView>
23
+ <View style={[StyleSheet.absoluteFill, style]}>{maskElement}</View>
24
+ </RNHostView>
25
+ </Mask.Content>
26
+ </Mask>
27
+ </Host>
28
+ </View>
29
+ );
30
+ }
31
+
32
+ export default MaskedView;
@@ -0,0 +1,34 @@
1
+ import { useEffect } from 'react';
2
+ import { View } from 'react-native';
3
+
4
+ import type { MaskedViewProps } from './types';
5
+
6
+ let warned = false;
7
+
8
+ /**
9
+ * Renders `children` with the alpha channel of `maskElement` applied as a mask:
10
+ * opaque pixels of `maskElement` reveal `children`, transparent pixels hide them.
11
+ *
12
+ * API-compatible with `@react-native-masked-view/masked-view`.
13
+ */
14
+ // This default file is used on platforms without a `.<platform>.tsx` override
15
+ // (notably web). It renders children unmasked and warns once.
16
+ export function MaskedView(props: MaskedViewProps) {
17
+ const { maskElement: _maskElement, children, style, ...rest } = props;
18
+ useEffect(() => {
19
+ if (!warned) {
20
+ warned = true;
21
+ console.warn(
22
+ '[@expo/ui/community/masked-view] MaskedView is not implemented on this platform. ' +
23
+ 'Children will render without a mask.'
24
+ );
25
+ }
26
+ }, []);
27
+ return (
28
+ <View {...rest} style={style}>
29
+ {children}
30
+ </View>
31
+ );
32
+ }
33
+
34
+ export default MaskedView;
@@ -0,0 +1,3 @@
1
+ export { MaskedView } from './MaskedView';
2
+ export { MaskedView as default } from './MaskedView';
3
+ export type { MaskedViewProps } from './types';
@@ -0,0 +1,19 @@
1
+ import type { ReactElement, ReactNode } from 'react';
2
+ import type { ViewProps } from 'react-native';
3
+
4
+ /**
5
+ * Drop-in props for `@react-native-masked-view/masked-view`'s `MaskedView`.
6
+ *
7
+ * @see https://github.com/callstack/masked-view
8
+ */
9
+ export interface MaskedViewProps extends ViewProps {
10
+ /**
11
+ * The element used as the mask. Only opaque pixels of `maskElement` make the
12
+ * masked content visible — transparent pixels hide it.
13
+ */
14
+ maskElement: ReactElement;
15
+ /**
16
+ * Content rendered behind the mask.
17
+ */
18
+ children?: ReactNode;
19
+ }
@@ -3,7 +3,7 @@ import * as React from 'react';
3
3
  import {
4
4
  extractPickerItems,
5
5
  PickerItem,
6
- type PickerWithItems,
6
+ type PickerItemProps,
7
7
  type PickerItemValue,
8
8
  type PickerProps,
9
9
  } from './types';
@@ -22,7 +22,7 @@ import { menuAnchor } from '../../jetpack-compose/modifiers';
22
22
  * A drop-in replacement for `@react-native-picker/picker` on Android.
23
23
  * Renders a Material 3 `ExposedDropdownMenuBox` wrapped in a Host.
24
24
  */
25
- function PickerImpl<T extends PickerItemValue>(props: PickerProps<T>) {
25
+ export function Picker<T extends PickerItemValue>(props: PickerProps<T>) {
26
26
  const { selectedValue, onValueChange, enabled, style, children, ref } = props;
27
27
  const items = extractPickerItems<T>(children);
28
28
  const [expanded, setExpanded] = React.useState(false);
@@ -52,7 +52,15 @@ function PickerImpl<T extends PickerItemValue>(props: PickerProps<T>) {
52
52
  setExpanded(false);
53
53
  }}>
54
54
  <DropdownMenuItem.Text>
55
- <Text>{item.label}</Text>
55
+ <Text
56
+ color={item.color}
57
+ style={{
58
+ fontFamily: item.fontFamily,
59
+ fontSize: item.fontSize,
60
+ background: item.backgroundColor,
61
+ }}>
62
+ {item.label}
63
+ </Text>
56
64
  </DropdownMenuItem.Text>
57
65
  </DropdownMenuItem>
58
66
  ))}
@@ -62,5 +70,4 @@ function PickerImpl<T extends PickerItemValue>(props: PickerProps<T>) {
62
70
  );
63
71
  }
64
72
 
65
- PickerImpl.displayName = 'Picker';
66
- export const Picker: PickerWithItems = Object.assign(PickerImpl, { Item: PickerItem });
73
+ Picker.Item = PickerItem as React.ComponentType<PickerItemProps>;
@@ -3,7 +3,7 @@ import * as React from 'react';
3
3
  import {
4
4
  extractPickerItems,
5
5
  PickerItem,
6
- type PickerWithItems,
6
+ type PickerItemProps,
7
7
  type PickerItemValue,
8
8
  type PickerProps,
9
9
  } from './types';
@@ -11,6 +11,7 @@ import { Host } from '../../swift-ui/Host';
11
11
  import { Picker as SwiftUIPicker } from '../../swift-ui/Picker';
12
12
  import { Text } from '../../swift-ui/Text';
13
13
  import {
14
+ backgroundOverlay,
14
15
  disabled as disabledModifier,
15
16
  fixedSize,
16
17
  foregroundStyle,
@@ -24,7 +25,7 @@ import { type ModifierConfig } from '../../types';
24
25
  * A drop-in replacement for `@react-native-picker/picker` on iOS.
25
26
  * Renders a SwiftUI wheel picker wrapped in a Host.
26
27
  */
27
- function PickerImpl<T extends PickerItemValue>(props: PickerProps<T>) {
28
+ export function Picker<T extends PickerItemValue>(props: PickerProps<T>) {
28
29
  const { selectedValue, onValueChange, enabled, style, children, ref } = props;
29
30
  const items = extractPickerItems<T>(children);
30
31
  const modifiers = [
@@ -55,8 +56,11 @@ function PickerImpl<T extends PickerItemValue>(props: PickerProps<T>) {
55
56
  if (item.color) {
56
57
  itemModifiers.push(foregroundStyle(item.color));
57
58
  }
58
- if (item.fontFamily) {
59
- itemModifiers.push(font({ family: item.fontFamily }));
59
+ if (item.fontFamily || item.fontSize != null) {
60
+ itemModifiers.push(font({ family: item.fontFamily, size: item.fontSize }));
61
+ }
62
+ if (item.backgroundColor) {
63
+ itemModifiers.push(backgroundOverlay({ color: item.backgroundColor }));
60
64
  }
61
65
  return (
62
66
  <Text key={String(item.value ?? index)} modifiers={itemModifiers}>
@@ -69,5 +73,4 @@ function PickerImpl<T extends PickerItemValue>(props: PickerProps<T>) {
69
73
  );
70
74
  }
71
75
 
72
- PickerImpl.displayName = 'Picker';
73
- export const Picker: PickerWithItems = Object.assign(PickerImpl, { Item: PickerItem });
76
+ Picker.Item = PickerItem as React.ComponentType<PickerItemProps>;
@@ -3,7 +3,7 @@ import * as React from 'react';
3
3
  import {
4
4
  extractPickerItems,
5
5
  PickerItem,
6
- type PickerWithItems,
6
+ type PickerItemProps,
7
7
  type PickerItemValue,
8
8
  type PickerProps,
9
9
  } from './types';
@@ -12,7 +12,7 @@ import {
12
12
  * A drop-in replacement for `@react-native-picker/picker` on web.
13
13
  * Renders a native `<select>` element.
14
14
  */
15
- function PickerImpl<T extends PickerItemValue>(props: PickerProps<T>) {
15
+ export function Picker<T extends PickerItemValue>(props: PickerProps<T>) {
16
16
  const { selectedValue, onValueChange, enabled, style, children, ref } = props;
17
17
  const items = extractPickerItems<T>(children);
18
18
  const selectRef = React.useRef<HTMLSelectElement>(null);
@@ -47,5 +47,4 @@ function PickerImpl<T extends PickerItemValue>(props: PickerProps<T>) {
47
47
  );
48
48
  }
49
49
 
50
- PickerImpl.displayName = 'Picker';
51
- export const Picker: PickerWithItems = Object.assign(PickerImpl, { Item: PickerItem });
50
+ Picker.Item = PickerItem as React.ComponentType<PickerItemProps>;
@@ -1,5 +1,5 @@
1
1
  import { Children, isValidElement, type Ref, type ReactNode, type ReactElement } from 'react';
2
- import type { StyleProp, ViewStyle } from 'react-native';
2
+ import { StyleSheet, type StyleProp, type TextStyle, type ViewStyle } from 'react-native';
3
3
 
4
4
  export type PickerItemValue = string | number | null;
5
5
 
@@ -7,7 +7,7 @@ export type PickerItemValue = string | number | null;
7
7
  * Props for the `Picker.Item` component.
8
8
  * Compatible with `@react-native-picker/picker`.
9
9
  */
10
- export type PickerItemProps<T extends PickerItemValue> = {
10
+ export type PickerItemProps<T extends PickerItemValue = PickerItemValue> = {
11
11
  /**
12
12
  * Display text for the item.
13
13
  */
@@ -17,15 +17,19 @@ export type PickerItemProps<T extends PickerItemValue> = {
17
17
  */
18
18
  value?: T;
19
19
  /**
20
- * Text color for the item.
21
- * @platform ios
20
+ * Text color for the item. Equivalent to setting `color` in the `style` prop.
22
21
  */
23
22
  color?: string;
24
23
  /**
25
- * Custom font family for the item.
26
- * @platform ios
24
+ * Custom font family for the item. Equivalent to setting `fontFamily` in the `style` prop.
27
25
  */
28
26
  fontFamily?: string;
27
+ /**
28
+ * Style applied to the item label. Only the following values take effect:
29
+ * `color`, `backgroundColor`, `fontFamily`, and `fontSize`. When also set
30
+ * via the top-level `color` or `fontFamily` props, values from `style` win.
31
+ */
32
+ style?: StyleProp<TextStyle>;
29
33
  /**
30
34
  * Whether the item is enabled.
31
35
  * @platform android
@@ -99,16 +103,13 @@ export type PickerRef = {
99
103
  blur: () => void;
100
104
  };
101
105
 
102
- export type PickerWithItems = {
103
- <T extends PickerItemValue>(props: PickerProps<T>): ReactElement | null;
104
- Item: typeof PickerItem;
105
- };
106
-
107
106
  export type ExtractedPickerItem<T extends PickerItemValue = PickerItemValue> = {
108
107
  label: string;
109
108
  value: T;
110
109
  color?: string;
110
+ backgroundColor?: string;
111
111
  fontFamily?: string;
112
+ fontSize?: number;
112
113
  enabled?: boolean;
113
114
  };
114
115
 
@@ -123,11 +124,16 @@ export function extractPickerItems<T extends PickerItemValue>(
123
124
  (child): child is ReactElement<PickerItemProps<T>> =>
124
125
  isValidElement(child) && child.type === PickerItem
125
126
  )
126
- .map(({ props: { label = '', value, color, fontFamily, enabled } }) => ({
127
- label,
128
- value: value as T,
129
- color,
130
- fontFamily,
131
- enabled,
132
- }));
127
+ .map(({ props: { label = '', value, color, fontFamily, style, enabled } }) => {
128
+ const flat = StyleSheet.flatten(style);
129
+ return {
130
+ label,
131
+ value: value as T,
132
+ color: (flat?.color as string | undefined) ?? color,
133
+ backgroundColor: flat?.backgroundColor as string | undefined,
134
+ fontFamily: flat?.fontFamily ?? fontFamily,
135
+ fontSize: flat?.fontSize,
136
+ enabled,
137
+ };
138
+ });
133
139
  }
@@ -22,12 +22,10 @@ export type DropdownMenuItemElementColors = {
22
22
  textColor?: ColorValue;
23
23
  /** Color of the text when the menu item is disabled. */
24
24
  disabledTextColor?: ColorValue;
25
- // TODO: At the moment IconView's tint color defaults to Color.Unspecified instead of LocalContentColor.current.
26
- // Thus the color override will not work for icons. At the moment icon color can only be set directly in IconView.
27
- // leadingIconColor?: ColorValue;
28
- // trailingIconColor?: ColorValue;
29
- // disabledLeadingIconColor?: ColorValue;
30
- // disabledTrailingIconColor?: ColorValue;
25
+ leadingIconColor?: ColorValue;
26
+ trailingIconColor?: ColorValue;
27
+ disabledLeadingIconColor?: ColorValue;
28
+ disabledTrailingIconColor?: ColorValue;
31
29
  };
32
30
 
33
31
  /**
@@ -10,20 +10,20 @@ export type HorizontalFloatingToolbarColors = {
10
10
  */
11
11
  toolbarContainerColor?: ColorValue;
12
12
 
13
- // Color of the toolbar content (icons/text).
14
- // TODO: At the moment IconView's tint color defaults to Color.Unspecified instead of LocalContentColor.current.
15
- // Thus the color override will not work.
16
- // toolbarContentColor?: ColorValue;
13
+ /**
14
+ * Color of the toolbar content (icons/text).
15
+ */
16
+ toolbarContentColor?: ColorValue;
17
17
 
18
18
  /**
19
19
  * Color of the floating action button container (background).
20
20
  */
21
21
  fabContainerColor?: ColorValue;
22
22
 
23
- // Color of the floating action button content (icon).
24
- // TODO: At the moment IconView's tint color defaults to Color.Unspecified instead of LocalContentColor.current.
25
- // Thus the color override will not work.
26
- // fabContentColor?: ColorValue;
23
+ /**
24
+ * Color of the floating action button content (icon).
25
+ */
26
+ fabContentColor?: ColorValue;
27
27
  };
28
28
 
29
29
  export type HorizontalFloatingToolbarProps = {
@@ -2,9 +2,11 @@ import { requireNativeView } from 'expo';
2
2
  import type { Ref } from 'react';
3
3
 
4
4
  import { type ModifierConfig, type ViewEvent } from '../../types';
5
- import type { PaddingValuesRecord } from '../Carousel';
5
+ import { type PaddingValuesRecord } from '../Carousel';
6
6
  import { createViewModifierEventListener } from '../modifiers/utils';
7
7
 
8
+ export type { PaddingValuesRecord };
9
+
8
10
  export type HorizontalPagerHandle = {
9
11
  /**
10
12
  * Mirrors Compose's `PagerState.animateScrollToPage`. Resolves when the
@@ -23,16 +23,22 @@ export type IconProps = {
23
23
  source: ImageSourcePropType;
24
24
 
25
25
  /**
26
- * The tint color to apply to the icon.
27
- * Accepts hex strings, named colors, or RGB arrays.
26
+ * The tint color to apply to the icon. Accepts hex strings, named colors,
27
+ * or RGB arrays.
28
+ *
29
+ * - When omitted, the icon inherits the color from the surrounding
30
+ * `LocalContentColor` (e.g. the toolbar/FAB content color).
31
+ * - When set to `null`, no tint is applied — the icon is drawn with its
32
+ * original colors (`Color.Unspecified`). Use this for multicolored icons.
28
33
  *
29
34
  * @example
30
35
  * ```tsx
31
36
  * <Icon source={require('./assets/star.xml')} tint="#007AFF" />
32
37
  * <Icon source={require('./assets/star.xml')} tint="blue" />
38
+ * <Icon source={require('./assets/multicolor.xml')} tint={null} />
33
39
  * ```
34
40
  */
35
- tint?: ColorValue;
41
+ tint?: ColorValue | null;
36
42
 
37
43
  /**
38
44
  * The size of the icon in density-independent pixels (dp).
@@ -80,8 +86,10 @@ export type IconProps = {
80
86
  /**
81
87
  * @hidden
82
88
  */
83
- export type NativeIconProps = Omit<IconProps, 'source'> & {
89
+ export type NativeIconProps = Omit<IconProps, 'source' | 'tint'> & {
84
90
  source: ImageResolvedAssetSource;
91
+ tint?: ColorValue;
92
+ inheritTint: boolean;
85
93
  };
86
94
 
87
95
  const IconNativeView: React.ComponentType<NativeIconProps> = requireNativeView(
@@ -90,12 +98,17 @@ const IconNativeView: React.ComponentType<NativeIconProps> = requireNativeView(
90
98
  );
91
99
 
92
100
  function transformIconProps(props: IconProps): NativeIconProps {
93
- const { source, modifiers, ...restProps } = props;
101
+ const { source, modifiers, tint, ...restProps } = props;
102
+ // Differentiate "tint not provided" (inherit `LocalContentColor`) from
103
+ // "tint explicitly null" (no tint, draw original colors).
104
+ const tintIsExplicitlyNull = 'tint' in props && tint === null;
94
105
 
95
106
  return {
96
107
  modifiers,
97
108
  ...(modifiers ? createViewModifierEventListener(modifiers) : undefined),
98
109
  ...restProps,
110
+ tint: tint ?? undefined,
111
+ inheritTint: !tintIsExplicitlyNull,
99
112
  source: Image.resolveAssetSource(source),
100
113
  };
101
114
  }
@@ -126,23 +126,15 @@ export type TextFieldColors = {
126
126
  errorSuffixColor?: ColorValue;
127
127
  };
128
128
 
129
- export type TextFieldValue = {
130
- text: string;
131
- selection: { start: number; end: number };
132
- };
133
-
134
- export type TextFieldValueLike = string | TextFieldValue;
135
-
136
129
  /** Shared props between `TextField` and `OutlinedTextField`. */
137
- type BaseTextFieldProps<T extends TextFieldValueLike = string> = {
130
+ type BaseTextFieldProps = {
138
131
  ref?: Ref<TextFieldRef>;
139
132
  /**
140
- * An observable state that holds the current value. Create one with either:
141
- * - `useNativeState('initial text')`.
142
- * - `useNativeState<TextFieldValue>({ text: '', selection: { start: 0, end: 0 } })`
143
- * If omitted, the field manages its own internal state.
133
+ * An observable state that holds the current text value. Create one with
134
+ * `useNativeState('initial text')`. If omitted, the field manages its own
135
+ * internal state.
144
136
  */
145
- value?: ObservableState<T>;
137
+ value?: ObservableState<string>;
146
138
  /** If true, the text field will be focused automatically when mounted. @default false */
147
139
  autoFocus?: boolean;
148
140
  /** @default true */
@@ -173,20 +165,18 @@ type BaseTextFieldProps<T extends TextFieldValueLike = string> = {
173
165
  };
174
166
 
175
167
  /**
176
- * Observable state the field writes the current selection to.
177
- * Create with `useNativeState({ start: 0, end: 0 })`.
178
- * Use `ref.setSelection(start, end)` to set programmatically.
179
- * @internal
168
+ * Observable state holding the current selection range. Create with
169
+ * `useNativeState({ start: 0, end: 0 })`. The field writes user-driven
170
+ * changes back to it, and writes from JS (or a worklet) update the
171
+ * cursor/selection in the field. Use `ref.setSelection(start, end)` for
172
+ * imperative one-shot updates.
180
173
  */
181
174
  selection?: ObservableState<{ start: number; end: number }>;
182
175
 
183
176
  /** Maximum number of characters allowed. Truncates natively as the user types. */
184
177
  maxLength?: number;
185
178
 
186
- /**
187
- * Called when the selection range changes.
188
- * @internal
189
- */
179
+ /** Called when the selection range changes. */
190
180
  onSelectionChange?: (selection: { start: number; end: number }) => void;
191
181
 
192
182
  /**
@@ -215,15 +205,12 @@ type BaseTextFieldProps<T extends TextFieldValueLike = string> = {
215
205
  keyboardOptions?: TextFieldKeyboardOptions;
216
206
  keyboardActions?: TextFieldKeyboardActions;
217
207
  /**
218
- * Fires whenever the value changes. The callback receives the same shape as `value`:
219
- * - `string` when `value` is a string observable (typing events only).
220
- * - `TextFieldValue` when `value` is a TextFieldValue observable (every gesture:
221
- * typing, tap-to-place, drag, select-all, arrow keys).
222
- *
223
- * If marked with the `'worklet'` directive, runs synchronously on the UI thread;
224
- * otherwise delivered asynchronously as a regular JS event.
208
+ * Fires whenever the text value changes. If marked with the `'worklet'`
209
+ * directive, runs synchronously on the UI thread; otherwise delivered
210
+ * asynchronously as a regular JS event. Use `onSelectionChange` (or read
211
+ * the `selection` observable) to react to selection-only changes.
225
212
  */
226
- onValueChange?: (value: T) => void;
213
+ onValueChange?: (value: string) => void;
227
214
  /** A callback triggered when the field gains or loses focus. */
228
215
  onFocusChanged?: (focused: boolean) => void;
229
216
  shape?: object;
@@ -232,14 +219,13 @@ type BaseTextFieldProps<T extends TextFieldValueLike = string> = {
232
219
  children?: React.ReactNode;
233
220
  };
234
221
 
235
- export type TextFieldProps<T extends TextFieldValueLike = string> = BaseTextFieldProps<T> & {
222
+ export type TextFieldProps = BaseTextFieldProps & {
236
223
  colors?: TextFieldColors;
237
224
  };
238
225
 
239
- export type OutlinedTextFieldProps<T extends TextFieldValueLike = string> =
240
- BaseTextFieldProps<T> & {
241
- colors?: TextFieldColors;
242
- };
226
+ export type OutlinedTextFieldProps = BaseTextFieldProps & {
227
+ colors?: TextFieldColors;
228
+ };
243
229
 
244
230
  // endregion Types
245
231
 
@@ -263,7 +249,7 @@ type NativeTextFieldProps = Omit<
263
249
  value?: number | null;
264
250
  selection?: number | null;
265
251
  onValueChangeSync?: number | null;
266
- } & ViewEvent<'onValueChange', TextFieldValue> &
252
+ } & ViewEvent<'onValueChange', { text: string; selection: { start: number; end: number } }> &
267
253
  ViewEvent<'onFocusChanged', { value: boolean }> &
268
254
  ViewEvent<'onSelectionChange', { start: number; end: number }> &
269
255
  ViewEvent<'onKeyboardAction', { action: string; value: string }>;
@@ -273,8 +259,8 @@ const TextFieldNativeView: React.ComponentType<NativeTextFieldProps> = requireNa
273
259
  'TextFieldView'
274
260
  );
275
261
 
276
- function useTransformedProps<T extends TextFieldValueLike>(
277
- props: TextFieldProps<T> | OutlinedTextFieldProps<T>,
262
+ function useTransformedProps(
263
+ props: TextFieldProps | OutlinedTextFieldProps,
278
264
  variant: 'filled' | 'outlined'
279
265
  ): NativeTextFieldProps {
280
266
  const {
@@ -289,8 +275,6 @@ function useTransformedProps<T extends TextFieldValueLike>(
289
275
  ...restProps
290
276
  } = props;
291
277
 
292
- const isStringMode = !value || typeof value.value === 'string';
293
-
294
278
  const isWorklet = !!onValueChange && !!worklets?.isWorkletFunction?.(onValueChange);
295
279
  const workletCallback = useWorkletProp(isWorklet ? onValueChange : undefined, 'onValueChange');
296
280
 
@@ -300,16 +284,11 @@ function useTransformedProps<T extends TextFieldValueLike>(
300
284
  ...restProps,
301
285
  variant,
302
286
  children,
303
- value: getStateId(value as ObservableState<TextFieldValueLike>),
287
+ value: getStateId(value),
304
288
  selection: getStateId(selection),
305
289
  onValueChangeSync: getStateId(workletCallback),
306
290
  onValueChange:
307
- !isWorklet && onValueChange
308
- ? (event) => {
309
- const payload = event.nativeEvent;
310
- onValueChange((isStringMode ? payload.text : payload) as T);
311
- }
312
- : undefined,
291
+ !isWorklet && onValueChange ? (event) => onValueChange(event.nativeEvent.text) : undefined,
313
292
  onFocusChanged: onFocusChanged ? (event) => onFocusChanged(event.nativeEvent.value) : undefined,
314
293
  onSelectionChange: onSelectionChange
315
294
  ? (event) => onSelectionChange({ start: event.nativeEvent.start, end: event.nativeEvent.end })
@@ -370,7 +349,7 @@ function SupportingText(props: { children: React.ReactNode }) {
370
349
  /**
371
350
  * A Material3 `TextField`.
372
351
  */
373
- function TextFieldComponent<T extends TextFieldValueLike = string>(props: TextFieldProps<T>) {
352
+ function TextFieldComponent(props: TextFieldProps) {
374
353
  return <TextFieldNativeView {...useTransformedProps(props, 'filled')} />;
375
354
  }
376
355
 
@@ -385,9 +364,7 @@ TextFieldComponent.SupportingText = SupportingText;
385
364
  /**
386
365
  * A Material3 `OutlinedTextField` with a transparent background and border outline.
387
366
  */
388
- function OutlinedTextFieldComponent<T extends TextFieldValueLike = string>(
389
- props: OutlinedTextFieldProps<T>
390
- ) {
367
+ function OutlinedTextFieldComponent(props: OutlinedTextFieldProps) {
391
368
  return <TextFieldNativeView {...useTransformedProps(props, 'outlined')} />;
392
369
  }
393
370
 
@@ -402,3 +379,6 @@ OutlinedTextFieldComponent.SupportingText = SupportingText;
402
379
  // endregion Components
403
380
 
404
381
  export { TextFieldComponent as TextField, OutlinedTextFieldComponent as OutlinedTextField };
382
+
383
+ // Exported for docs api data
384
+ export { type ObservableState };