@expo/ui 58.0.21 → 58.0.22
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.
- package/CHANGELOG.md +22 -0
- package/README.md +86 -2
- package/android/build.gradle +2 -2
- package/android/src/main/java/expo/modules/ui/CompositionLocalProviderView.kt +26 -0
- package/android/src/main/java/expo/modules/ui/ExpoUIModule.kt +12 -0
- package/android/src/main/java/expo/modules/ui/HostView.kt +4 -1
- package/android/src/main/java/expo/modules/ui/MaskView.kt +3 -2
- package/android/src/main/java/expo/modules/ui/ModifierRegistry.kt +3 -1
- package/android/src/main/java/expo/modules/ui/RNHostView.kt +11 -7
- package/android/src/main/java/expo/modules/ui/SwitchView.kt +6 -1
- package/android/src/main/java/expo/modules/ui/TopAppBarView.kt +62 -0
- package/android/src/main/java/expo/modules/ui/colors/MaterialColors.kt +61 -0
- package/build/community/bottom-sheet/BottomSheet.ios.js +8 -3
- package/build/community/bottom-sheet/BottomSheet.ios.js.map +1 -1
- package/build/community/pager-view/PagerView.ios.js +25 -8
- package/build/community/pager-view/PagerView.ios.js.map +1 -1
- package/build/community/segmented-control/SegmentedControl.ios.js +11 -2
- package/build/community/segmented-control/SegmentedControl.ios.js.map +1 -1
- package/build/community/segmented-control/types.d.ts +5 -1
- package/build/community/segmented-control/types.js.map +1 -1
- package/build/jetpack-compose/CompositionLocalProvider/index.d.ts +28 -0
- package/build/jetpack-compose/CompositionLocalProvider/index.js +15 -0
- package/build/jetpack-compose/CompositionLocalProvider/index.js.map +1 -0
- package/build/jetpack-compose/Host/index.d.ts +8 -0
- package/build/jetpack-compose/Host/index.js +38 -5
- package/build/jetpack-compose/Host/index.js.map +1 -1
- package/build/jetpack-compose/Switch/index.d.ts +2 -0
- package/build/jetpack-compose/Switch/index.js +1 -0
- package/build/jetpack-compose/Switch/index.js.map +1 -1
- package/build/jetpack-compose/TopAppBar/index.d.ts +72 -0
- package/build/jetpack-compose/TopAppBar/index.js +45 -0
- package/build/jetpack-compose/TopAppBar/index.js.map +1 -0
- package/build/jetpack-compose/index.d.ts +2 -0
- package/build/jetpack-compose/index.js +2 -0
- package/build/jetpack-compose/index.js.map +1 -1
- package/build/jetpack-compose/modifiers/index.d.ts +5 -1
- package/build/jetpack-compose/modifiers/index.js +6 -2
- package/build/jetpack-compose/modifiers/index.js.map +1 -1
- package/build/swift-ui/BottomSheet/index.d.ts +6 -0
- package/build/swift-ui/BottomSheet/index.js +9 -3
- package/build/swift-ui/BottomSheet/index.js.map +1 -1
- package/build/universal/Checkbox/index.android.js +16 -4
- package/build/universal/Checkbox/index.android.js.map +1 -1
- package/build/universal/ScrollView/index.ios.js +12 -6
- package/build/universal/ScrollView/index.ios.js.map +1 -1
- package/build/universal/Switch/index.android.js +17 -4
- package/build/universal/Switch/index.android.js.map +1 -1
- package/build/universal/Switch/index.js +1 -0
- package/build/universal/Switch/index.js.map +1 -1
- package/build/universal/Text/index.js +2 -2
- package/build/universal/Text/index.js.map +1 -1
- package/build/universal/webUtils.js +4 -0
- package/build/universal/webUtils.js.map +1 -1
- package/ios/BottomSheetView.swift +11 -2
- package/ios/DatePickerView.swift +134 -9
- package/ios/Modifiers/SelectedSegmentTintColorModifier.swift +86 -0
- package/ios/Modifiers/ViewModifierRegistry.swift +4 -0
- package/ios/RNHostView.swift +34 -16
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/{58.0.21/expo.modules.ui-58.0.21-sources.jar → 58.0.22/expo.modules.ui-58.0.22-sources.jar} +0 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.22/expo.modules.ui-58.0.22-sources.jar.md5 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.22/expo.modules.ui-58.0.22-sources.jar.sha1 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.22/expo.modules.ui-58.0.22-sources.jar.sha256 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.22/expo.modules.ui-58.0.22-sources.jar.sha512 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.22/expo.modules.ui-58.0.22.aar +0 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.22/expo.modules.ui-58.0.22.aar.md5 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.22/expo.modules.ui-58.0.22.aar.sha1 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.22/expo.modules.ui-58.0.22.aar.sha256 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.22/expo.modules.ui-58.0.22.aar.sha512 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/{58.0.21/expo.modules.ui-58.0.21.module → 58.0.22/expo.modules.ui-58.0.22.module} +22 -22
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.22/expo.modules.ui-58.0.22.module.md5 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.22/expo.modules.ui-58.0.22.module.sha1 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.22/expo.modules.ui-58.0.22.module.sha256 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.22/expo.modules.ui-58.0.22.module.sha512 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/{58.0.21/expo.modules.ui-58.0.21.pom → 58.0.22/expo.modules.ui-58.0.22.pom} +1 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.22/expo.modules.ui-58.0.22.pom.md5 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.22/expo.modules.ui-58.0.22.pom.sha1 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.22/expo.modules.ui-58.0.22.pom.sha256 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.22/expo.modules.ui-58.0.22.pom.sha512 +1 -0
- package/package.json +2 -2
- package/src/community/bottom-sheet/BottomSheet.ios.tsx +7 -3
- package/src/community/pager-view/PagerView.ios.tsx +25 -8
- package/src/community/segmented-control/SegmentedControl.ios.tsx +13 -1
- package/src/community/segmented-control/types.tsx +5 -1
- package/src/jetpack-compose/CompositionLocalProvider/index.tsx +43 -0
- package/src/jetpack-compose/Host/index.tsx +50 -4
- package/src/jetpack-compose/Switch/index.tsx +4 -0
- package/src/jetpack-compose/TopAppBar/index.tsx +113 -0
- package/src/jetpack-compose/index.ts +2 -0
- package/src/jetpack-compose/modifiers/index.ts +11 -3
- package/src/swift-ui/BottomSheet/index.tsx +24 -3
- package/src/universal/Checkbox/index.android.tsx +24 -5
- package/src/universal/ScrollView/index.ios.tsx +14 -3
- package/src/universal/Switch/index.android.tsx +23 -4
- package/src/universal/Switch/index.tsx +1 -0
- package/src/universal/Text/index.tsx +2 -2
- package/src/universal/webUtils.ts +4 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.21/expo.modules.ui-58.0.21-sources.jar.md5 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.21/expo.modules.ui-58.0.21-sources.jar.sha1 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.21/expo.modules.ui-58.0.21-sources.jar.sha256 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.21/expo.modules.ui-58.0.21-sources.jar.sha512 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.21/expo.modules.ui-58.0.21.aar +0 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.21/expo.modules.ui-58.0.21.aar.md5 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.21/expo.modules.ui-58.0.21.aar.sha1 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.21/expo.modules.ui-58.0.21.aar.sha256 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.21/expo.modules.ui-58.0.21.aar.sha512 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.21/expo.modules.ui-58.0.21.module.md5 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.21/expo.modules.ui-58.0.21.module.sha1 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.21/expo.modules.ui-58.0.21.module.sha256 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.21/expo.modules.ui-58.0.21.module.sha512 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.21/expo.modules.ui-58.0.21.pom.md5 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.21/expo.modules.ui-58.0.21.pom.sha1 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.21/expo.modules.ui-58.0.21.pom.sha256 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.21/expo.modules.ui-58.0.21.pom.sha512 +0 -1
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"component": {
|
|
4
4
|
"group": "expo.modules.ui",
|
|
5
5
|
"module": "expo.modules.ui",
|
|
6
|
-
"version": "58.0.
|
|
6
|
+
"version": "58.0.22",
|
|
7
7
|
"attributes": {
|
|
8
8
|
"org.gradle.status": "release"
|
|
9
9
|
}
|
|
@@ -24,13 +24,13 @@
|
|
|
24
24
|
},
|
|
25
25
|
"files": [
|
|
26
26
|
{
|
|
27
|
-
"name": "expo.modules.ui-58.0.
|
|
28
|
-
"url": "expo.modules.ui-58.0.
|
|
29
|
-
"size":
|
|
30
|
-
"sha512": "
|
|
31
|
-
"sha256": "
|
|
32
|
-
"sha1": "
|
|
33
|
-
"md5": "
|
|
27
|
+
"name": "expo.modules.ui-58.0.22.aar",
|
|
28
|
+
"url": "expo.modules.ui-58.0.22.aar",
|
|
29
|
+
"size": 1882334,
|
|
30
|
+
"sha512": "0a89be2233ee1dd16b1cb671e0694d6d9a428f7f199e3e3efcdd621090c541d435478b39402a6da271373a70cbed690f989e938ebcbbcd35b740e1bf240dfb64",
|
|
31
|
+
"sha256": "59cc7013ee6674f030b4f81641fa80fb1829815d6ab5a7903f0e7479e6adb96e",
|
|
32
|
+
"sha1": "7acd625f3cd50ad228fac699424fcff3c77942bb",
|
|
33
|
+
"md5": "6b7272e2ff6f2f155c76a4e7a3341af6"
|
|
34
34
|
}
|
|
35
35
|
]
|
|
36
36
|
},
|
|
@@ -141,13 +141,13 @@
|
|
|
141
141
|
],
|
|
142
142
|
"files": [
|
|
143
143
|
{
|
|
144
|
-
"name": "expo.modules.ui-58.0.
|
|
145
|
-
"url": "expo.modules.ui-58.0.
|
|
146
|
-
"size":
|
|
147
|
-
"sha512": "
|
|
148
|
-
"sha256": "
|
|
149
|
-
"sha1": "
|
|
150
|
-
"md5": "
|
|
144
|
+
"name": "expo.modules.ui-58.0.22.aar",
|
|
145
|
+
"url": "expo.modules.ui-58.0.22.aar",
|
|
146
|
+
"size": 1882334,
|
|
147
|
+
"sha512": "0a89be2233ee1dd16b1cb671e0694d6d9a428f7f199e3e3efcdd621090c541d435478b39402a6da271373a70cbed690f989e938ebcbbcd35b740e1bf240dfb64",
|
|
148
|
+
"sha256": "59cc7013ee6674f030b4f81641fa80fb1829815d6ab5a7903f0e7479e6adb96e",
|
|
149
|
+
"sha1": "7acd625f3cd50ad228fac699424fcff3c77942bb",
|
|
150
|
+
"md5": "6b7272e2ff6f2f155c76a4e7a3341af6"
|
|
151
151
|
}
|
|
152
152
|
]
|
|
153
153
|
},
|
|
@@ -161,13 +161,13 @@
|
|
|
161
161
|
},
|
|
162
162
|
"files": [
|
|
163
163
|
{
|
|
164
|
-
"name": "expo.modules.ui-58.0.
|
|
165
|
-
"url": "expo.modules.ui-58.0.
|
|
166
|
-
"size":
|
|
167
|
-
"sha512": "
|
|
168
|
-
"sha256": "
|
|
169
|
-
"sha1": "
|
|
170
|
-
"md5": "
|
|
164
|
+
"name": "expo.modules.ui-58.0.22-sources.jar",
|
|
165
|
+
"url": "expo.modules.ui-58.0.22-sources.jar",
|
|
166
|
+
"size": 115385,
|
|
167
|
+
"sha512": "6c228c1dcbe9ee23cca52ba20eb724d39d18533e6c31ad738ab5738e5dfc64432b7c79363f7ff772f019f8bda955d0d38ccb3f4331d3236e4beddd70e6e426f4",
|
|
168
|
+
"sha256": "2487d657c68bf866e677ef379bc97b7de37edb41eb173b6d8d938b81bfcb2293",
|
|
169
|
+
"sha1": "a1628408f238e018286c0c9887ebb3cf9912577d",
|
|
170
|
+
"md5": "3367880bd9dfec581496b8b5087f9ae0"
|
|
171
171
|
}
|
|
172
172
|
]
|
|
173
173
|
}
|
package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.22/expo.modules.ui-58.0.22.module.md5
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
9c0bd2c795559f590e2efcec2bfbdd40
|
package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.22/expo.modules.ui-58.0.22.module.sha1
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0ca2cbc2529c5570d31a5cbd827f2b9c58602e25
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
113bc88759a3cbbb991dc12571a1b53722855970232edf6508469dc52c822423
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
ef4e3b199c2d69deab60d857ef81dc8c786f2bdc5a4321e9397111507d9f235c8575cd91289d8c612666b901cadd7aeca414aece1769dca15ec2088f5b8c0cb4
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
<modelVersion>4.0.0</modelVersion>
|
|
10
10
|
<groupId>expo.modules.ui</groupId>
|
|
11
11
|
<artifactId>expo.modules.ui</artifactId>
|
|
12
|
-
<version>58.0.
|
|
12
|
+
<version>58.0.22</version>
|
|
13
13
|
<packaging>aar</packaging>
|
|
14
14
|
<name>expo.modules.ui</name>
|
|
15
15
|
<url>https://github.com/expo/expo</url>
|
package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.22/expo.modules.ui-58.0.22.pom.md5
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
1fc7977e8379c6c817fa7524ff7db31f
|
package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.22/expo.modules.ui-58.0.22.pom.sha1
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
2a13240cd35aa73ed4d9787b4a70cbe0453431dd
|
package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.22/expo.modules.ui-58.0.22.pom.sha256
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
c15bb9d564da8ea75a501e89d3c855df5294966438d81168675388dab731e23e
|
package/local-maven-repo/expo/modules/ui/expo.modules.ui/58.0.22/expo.modules.ui-58.0.22.pom.sha512
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
a1a75142fcd486afa2e7bd2f27cdc21e1997cb309fb762963b61e65c88fd6e5a62af5234f448b485b0a2f3081f74eb1c8664e9d08a1f1a445ca2c62639e7f3f1
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@expo/ui",
|
|
3
|
-
"version": "58.0.
|
|
3
|
+
"version": "58.0.22",
|
|
4
4
|
"description": "A collection of UI components",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Jetpack Compose",
|
|
@@ -141,7 +141,7 @@
|
|
|
141
141
|
},
|
|
142
142
|
"devDependencies": {
|
|
143
143
|
"@babel/core": "^7.26.0",
|
|
144
|
-
"@expo/internal-scripts": "58.0.
|
|
144
|
+
"@expo/internal-scripts": "58.0.4",
|
|
145
145
|
"@playwright/test": "^1.59.0",
|
|
146
146
|
"@testing-library/react": "^16.3.0",
|
|
147
147
|
"@testing-library/react-native": "^14.0.1",
|
|
@@ -135,10 +135,14 @@ export function BottomSheet(props: BottomSheetProps) {
|
|
|
135
135
|
} else if (indexProp >= 0) {
|
|
136
136
|
closedRef.current = false;
|
|
137
137
|
setIsPresented(true);
|
|
138
|
-
const clampedIndex = Math.min(indexProp, detents.length - 1);
|
|
139
|
-
setCurrentIndex(clampedIndex);
|
|
140
|
-
currentIndexRef.current = clampedIndex;
|
|
141
138
|
}
|
|
139
|
+
}, [indexProp]);
|
|
140
|
+
|
|
141
|
+
useEffect(() => {
|
|
142
|
+
const requestedIndex = indexProp >= 0 ? indexProp : currentIndexRef.current;
|
|
143
|
+
const clampedIndex = Math.min(requestedIndex, detents.length - 1);
|
|
144
|
+
setCurrentIndex(clampedIndex);
|
|
145
|
+
currentIndexRef.current = clampedIndex;
|
|
142
146
|
}, [indexProp, detents.length]);
|
|
143
147
|
|
|
144
148
|
const handlePresentedChange = useCallback((presented: boolean) => {
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
useState,
|
|
10
10
|
type ReactElement,
|
|
11
11
|
} from 'react';
|
|
12
|
-
import { Platform } from 'react-native';
|
|
12
|
+
import { Platform, StyleSheet, View } from 'react-native';
|
|
13
13
|
|
|
14
14
|
import { useNativeState, worklets } from '../../State';
|
|
15
15
|
import { Group } from '../../swift-ui/Group';
|
|
@@ -89,6 +89,12 @@ export function PagerView(props: PagerViewProps) {
|
|
|
89
89
|
const pageCountRef = useRef(0);
|
|
90
90
|
pageCountRef.current = pageCount;
|
|
91
91
|
|
|
92
|
+
const isScrollingRef = useRef(false);
|
|
93
|
+
// The SwiftUI scroll doesn't cancel React Native touches on its pages. Like
|
|
94
|
+
// React Native's `ScrollView`, take the touch from the page content while
|
|
95
|
+
// the pager moves, so a swipe or a tap that stops it doesn't press anything.
|
|
96
|
+
const shouldCaptureTouch = () => isScrollingRef.current;
|
|
97
|
+
|
|
92
98
|
// Clamp on first render — out-of-range initials produce an id that matches
|
|
93
99
|
// no `Group`, leaving `.scrollPosition(id:)` silently stuck at 0.
|
|
94
100
|
const [clampedInitialPage] = useState(() => {
|
|
@@ -188,17 +194,24 @@ export function PagerView(props: PagerViewProps) {
|
|
|
188
194
|
);
|
|
189
195
|
const geometryModifier = useScrollGeometryChange(handleScrollGeometry);
|
|
190
196
|
|
|
191
|
-
const phaseModifier =
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
197
|
+
const phaseModifier = onScrollPhaseChange((phase) => {
|
|
198
|
+
const pageScrollState = phaseToPageState(phase);
|
|
199
|
+
isScrollingRef.current = pageScrollState !== 'idle';
|
|
200
|
+
onPageScrollStateChanged?.(wrapNativeEvent({ pageScrollState }));
|
|
201
|
+
});
|
|
196
202
|
|
|
197
203
|
const pages = validChildren.map((child, index) => (
|
|
198
204
|
<Group
|
|
199
205
|
key={child.key ?? String(index)}
|
|
200
206
|
modifiers={[containerRelativeFrame({ axes: 'horizontal' }), id(String(index))]}>
|
|
201
|
-
<RNHostView>
|
|
207
|
+
<RNHostView>
|
|
208
|
+
<View
|
|
209
|
+
style={styles.page}
|
|
210
|
+
onStartShouldSetResponderCapture={shouldCaptureTouch}
|
|
211
|
+
onMoveShouldSetResponderCapture={shouldCaptureTouch}>
|
|
212
|
+
{child}
|
|
213
|
+
</View>
|
|
214
|
+
</RNHostView>
|
|
202
215
|
</Group>
|
|
203
216
|
));
|
|
204
217
|
|
|
@@ -209,7 +222,7 @@ export function PagerView(props: PagerViewProps) {
|
|
|
209
222
|
scrollDisabled(!scrollEnabledState),
|
|
210
223
|
scrollPosition(activePageState, { onChange: handleScrolledIDChange }),
|
|
211
224
|
...(geometryModifier ? [geometryModifier] : []),
|
|
212
|
-
|
|
225
|
+
phaseModifier,
|
|
213
226
|
];
|
|
214
227
|
|
|
215
228
|
return (
|
|
@@ -271,3 +284,7 @@ function warnIfPreIOS18ScrollCallbacksDropped(
|
|
|
271
284
|
);
|
|
272
285
|
}
|
|
273
286
|
}
|
|
287
|
+
|
|
288
|
+
const styles = StyleSheet.create({
|
|
289
|
+
page: { flex: 1 },
|
|
290
|
+
});
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import { Host } from '../../swift-ui/Host';
|
|
2
2
|
import { Picker } from '../../swift-ui/Picker';
|
|
3
3
|
import { Text } from '../../swift-ui/Text';
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
accessibilityLabel as accessibilityLabelModifier,
|
|
6
|
+
disabled as disabledModifier,
|
|
7
|
+
} from '../../swift-ui/modifiers';
|
|
8
|
+
import { createModifier } from '../../swift-ui/modifiers/createModifier';
|
|
5
9
|
import { environment } from '../../swift-ui/modifiers/environment';
|
|
6
10
|
import { pickerStyle } from '../../swift-ui/modifiers/pickerStyle';
|
|
7
11
|
import { tag } from '../../swift-ui/modifiers/tag';
|
|
@@ -15,15 +19,23 @@ export function SegmentedControl(props: SegmentedControlProps) {
|
|
|
15
19
|
enabled = true,
|
|
16
20
|
onChange,
|
|
17
21
|
onValueChange,
|
|
22
|
+
tintColor,
|
|
18
23
|
appearance,
|
|
19
24
|
style,
|
|
20
25
|
testID,
|
|
26
|
+
accessibilityLabel,
|
|
21
27
|
} = props;
|
|
22
28
|
|
|
23
29
|
const modifiers: ModifierConfig[] = [pickerStyle('segmented')];
|
|
24
30
|
if (!enabled) {
|
|
25
31
|
modifiers.push(disabledModifier());
|
|
26
32
|
}
|
|
33
|
+
if (accessibilityLabel) {
|
|
34
|
+
modifiers.push(accessibilityLabelModifier(accessibilityLabel));
|
|
35
|
+
}
|
|
36
|
+
if (tintColor) {
|
|
37
|
+
modifiers.push(createModifier('selectedSegmentTintColor', { color: tintColor }));
|
|
38
|
+
}
|
|
27
39
|
if (appearance) {
|
|
28
40
|
modifiers.push(environment('colorScheme', appearance));
|
|
29
41
|
}
|
|
@@ -43,7 +43,6 @@ export interface SegmentedControlProps {
|
|
|
43
43
|
onValueChange?: (value: string) => void;
|
|
44
44
|
/**
|
|
45
45
|
* Accent color of the control.
|
|
46
|
-
* @platform android, web
|
|
47
46
|
*/
|
|
48
47
|
tintColor?: string;
|
|
49
48
|
/**
|
|
@@ -52,6 +51,11 @@ export interface SegmentedControlProps {
|
|
|
52
51
|
appearance?: 'dark' | 'light';
|
|
53
52
|
style?: StyleProp<ViewStyle>;
|
|
54
53
|
testID?: string;
|
|
54
|
+
/**
|
|
55
|
+
* The name of the control that screen readers announce.
|
|
56
|
+
* @platform ios
|
|
57
|
+
*/
|
|
58
|
+
accessibilityLabel?: string;
|
|
55
59
|
}
|
|
56
60
|
|
|
57
61
|
/**
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { requireNativeView } from 'expo';
|
|
2
|
+
import type { ReactNode } from 'react';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Composition local values that `CompositionLocalProvider` can provide.
|
|
6
|
+
*/
|
|
7
|
+
export type CompositionLocalValues = {
|
|
8
|
+
/**
|
|
9
|
+
* The minimum size, in dp, that Material components such as `Button`, `IconButton`, `Checkbox`, and
|
|
10
|
+
* `Switch` reserve for their touch target. Maps to `LocalMinimumInteractiveComponentSize`.
|
|
11
|
+
* Set it to `0` to let these components be smaller than Material's default of 48dp.
|
|
12
|
+
*/
|
|
13
|
+
minimumInteractiveComponentSize?: number;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export type CompositionLocalProviderProps = {
|
|
17
|
+
/**
|
|
18
|
+
* The values to provide to the children.
|
|
19
|
+
*/
|
|
20
|
+
values: CompositionLocalValues;
|
|
21
|
+
/**
|
|
22
|
+
* The content that receives the values.
|
|
23
|
+
*/
|
|
24
|
+
children?: ReactNode;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
type NativeCompositionLocalProviderProps = CompositionLocalValues & {
|
|
28
|
+
children?: ReactNode;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const CompositionLocalProviderNativeView: React.ComponentType<NativeCompositionLocalProviderProps> =
|
|
32
|
+
requireNativeView('ExpoUI', 'CompositionLocalProviderView');
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Provides composition local values to its children, like Jetpack Compose's `CompositionLocalProvider`.
|
|
36
|
+
* It adds no layout of its own, so children keep modifiers such as `weight` from the parent `Row`
|
|
37
|
+
* or `Column`.
|
|
38
|
+
*/
|
|
39
|
+
export function CompositionLocalProvider({ values, children }: CompositionLocalProviderProps) {
|
|
40
|
+
return (
|
|
41
|
+
<CompositionLocalProviderNativeView {...values}>{children}</CompositionLocalProviderNativeView>
|
|
42
|
+
);
|
|
43
|
+
}
|
|
@@ -6,13 +6,19 @@ import {
|
|
|
6
6
|
type StyleProp,
|
|
7
7
|
type ViewStyle,
|
|
8
8
|
I18nManager,
|
|
9
|
+
processColor,
|
|
9
10
|
useColorScheme as useRNColorScheme,
|
|
10
11
|
} from 'react-native';
|
|
11
12
|
|
|
12
13
|
import { NativeTreeContext, useWarnIfNestedHost } from '../../NativeTreeContext';
|
|
13
14
|
import { TextInputHostProvider, useTextInputHostRef } from '../../keyboard';
|
|
14
15
|
import { useMergeRefs } from '../../utils/useMergeRefs';
|
|
15
|
-
import {
|
|
16
|
+
import {
|
|
17
|
+
getMaterialColors,
|
|
18
|
+
HostPaletteContext,
|
|
19
|
+
type MaterialColors,
|
|
20
|
+
type RgbaHex,
|
|
21
|
+
} from '../colors';
|
|
16
22
|
import { type PrimitiveBaseProps } from '../layout';
|
|
17
23
|
|
|
18
24
|
export interface HostProps extends PrimitiveBaseProps {
|
|
@@ -52,6 +58,14 @@ export interface HostProps extends PrimitiveBaseProps {
|
|
|
52
58
|
*/
|
|
53
59
|
seedColor?: ColorValue;
|
|
54
60
|
|
|
61
|
+
/**
|
|
62
|
+
* Material 3 color roles that replace the matching roles of the palette from
|
|
63
|
+
* `colorScheme` and `seedColor`. Roles you omit keep their palette value.
|
|
64
|
+
* The overrides theme Compose children and are returned by `useMaterialColors()`
|
|
65
|
+
* in the same `#RRGGBBAA` form as the other roles.
|
|
66
|
+
*/
|
|
67
|
+
colorOverrides?: Partial<MaterialColors>;
|
|
68
|
+
|
|
55
69
|
/**
|
|
56
70
|
* The layout direction for the content.
|
|
57
71
|
* Defaults to the current locale direction from I18nManager.
|
|
@@ -93,6 +107,7 @@ export function Host(props: HostProps) {
|
|
|
93
107
|
layoutDirection,
|
|
94
108
|
colorScheme,
|
|
95
109
|
seedColor,
|
|
110
|
+
colorOverrides,
|
|
96
111
|
ref,
|
|
97
112
|
children,
|
|
98
113
|
...restProps
|
|
@@ -101,10 +116,19 @@ export function Host(props: HostProps) {
|
|
|
101
116
|
|
|
102
117
|
const systemScheme = useRNColorScheme();
|
|
103
118
|
const resolvedScheme = schemeString ?? (systemScheme === 'dark' ? 'dark' : 'light');
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
119
|
+
// Key on the normalized values, not the object, so an inline `colorOverrides` object keeps
|
|
120
|
+
// the palette from `useMaterialColors()` reference-stable across re-renders.
|
|
121
|
+
const overridesKey = colorOverrides
|
|
122
|
+
? JSON.stringify(normalizeColorOverrides(colorOverrides))
|
|
123
|
+
: null;
|
|
124
|
+
const normalizedOverrides = useMemo<Partial<MaterialColors> | undefined>(
|
|
125
|
+
() => (overridesKey ? JSON.parse(overridesKey) : undefined),
|
|
126
|
+
[overridesKey]
|
|
107
127
|
);
|
|
128
|
+
const palette = useMemo(() => {
|
|
129
|
+
const basePalette = getMaterialColors({ scheme: resolvedScheme, seedColor });
|
|
130
|
+
return normalizedOverrides ? { ...basePalette, ...normalizedOverrides } : basePalette;
|
|
131
|
+
}, [resolvedScheme, seedColor, normalizedOverrides]);
|
|
108
132
|
const hostRef = useTextInputHostRef();
|
|
109
133
|
const mergedRef = useMergeRefs(ref, hostRef);
|
|
110
134
|
useWarnIfNestedHost('Jetpack Compose');
|
|
@@ -123,6 +147,7 @@ export function Host(props: HostProps) {
|
|
|
123
147
|
}
|
|
124
148
|
colorScheme={schemeString}
|
|
125
149
|
seedColor={seedColor}
|
|
150
|
+
colorOverrides={normalizedOverrides}
|
|
126
151
|
onLayoutContent={onLayoutContent}
|
|
127
152
|
layoutDirection={
|
|
128
153
|
layoutDirection ?? (I18nManager.getConstants().isRTL ? 'rightToLeft' : 'leftToRight')
|
|
@@ -134,3 +159,24 @@ export function Host(props: HostProps) {
|
|
|
134
159
|
</HostPaletteContext.Provider>
|
|
135
160
|
);
|
|
136
161
|
}
|
|
162
|
+
|
|
163
|
+
function normalizeColorOverrides(overrides: Partial<MaterialColors>): Partial<MaterialColors> {
|
|
164
|
+
const normalized: Partial<MaterialColors> = {};
|
|
165
|
+
for (const [role, color] of Object.entries(overrides) as [keyof MaterialColors, RgbaHex][]) {
|
|
166
|
+
const hex = color != null ? toRgbaHex(color) : null;
|
|
167
|
+
if (hex) {
|
|
168
|
+
normalized[role] = hex;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
return normalized;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// `processColor` returns `0xAARRGGBB`; the palette uses `#RRGGBBAA` like native `toTokenMap()`.
|
|
175
|
+
function toRgbaHex(color: RgbaHex): RgbaHex | null {
|
|
176
|
+
const argb = processColor(color);
|
|
177
|
+
if (typeof argb !== 'number') {
|
|
178
|
+
return null;
|
|
179
|
+
}
|
|
180
|
+
const rgba = ((argb << 8) | (argb >>> 24)) >>> 0;
|
|
181
|
+
return `#${rgba.toString(16).padStart(8, '0').toUpperCase()}`;
|
|
182
|
+
}
|
|
@@ -39,6 +39,8 @@ export interface SwitchProps {
|
|
|
39
39
|
enabled?: boolean;
|
|
40
40
|
/**
|
|
41
41
|
* Callback function that is called when the checked state changes.
|
|
42
|
+
* When omitted, the switch is not interactive on its own, so a parent with the
|
|
43
|
+
* `toggleable` modifier can handle input and accessibility for it.
|
|
42
44
|
*/
|
|
43
45
|
onCheckedChange?: (value: boolean) => void;
|
|
44
46
|
/**
|
|
@@ -58,6 +60,7 @@ export interface SwitchProps {
|
|
|
58
60
|
|
|
59
61
|
type NativeSwitchProps = Omit<SwitchProps, 'onCheckedChange' | 'children'> & {
|
|
60
62
|
children?: React.ReactNode;
|
|
63
|
+
nativeClickable: boolean;
|
|
61
64
|
onCheckedChange: (event: NativeSyntheticEvent<{ value: boolean }>) => void;
|
|
62
65
|
};
|
|
63
66
|
|
|
@@ -94,6 +97,7 @@ function transformSwitchProps(props: SwitchProps): Omit<NativeSwitchProps, 'chil
|
|
|
94
97
|
modifiers,
|
|
95
98
|
...(modifiers ? createViewModifierEventListener(modifiers) : undefined),
|
|
96
99
|
...restProps,
|
|
100
|
+
nativeClickable: onCheckedChange != null,
|
|
97
101
|
onCheckedChange: ({ nativeEvent: { value } }) => {
|
|
98
102
|
onCheckedChange?.(value);
|
|
99
103
|
},
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { requireNativeView } from 'expo';
|
|
2
|
+
import type { ColorValue } from 'react-native';
|
|
3
|
+
|
|
4
|
+
import type { ExpoModifier } from '../../types';
|
|
5
|
+
import type { PaddingValuesRecord } from '../Carousel';
|
|
6
|
+
import { createViewModifierEventListener } from '../modifiers/utils';
|
|
7
|
+
|
|
8
|
+
export type { PaddingValuesRecord };
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Colors for the top app bar.
|
|
12
|
+
*/
|
|
13
|
+
export type TopAppBarColors = {
|
|
14
|
+
/**
|
|
15
|
+
* Color of the container (background).
|
|
16
|
+
*/
|
|
17
|
+
containerColor?: ColorValue;
|
|
18
|
+
/**
|
|
19
|
+
* Color of the navigation icon.
|
|
20
|
+
*/
|
|
21
|
+
navigationIconContentColor?: ColorValue;
|
|
22
|
+
/**
|
|
23
|
+
* Color of the title.
|
|
24
|
+
*/
|
|
25
|
+
titleContentColor?: ColorValue;
|
|
26
|
+
/**
|
|
27
|
+
* Color of the action icons.
|
|
28
|
+
*/
|
|
29
|
+
actionIconContentColor?: ColorValue;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export interface TopAppBarProps {
|
|
33
|
+
/**
|
|
34
|
+
* Colors for the app bar. Unset colors use `TopAppBarDefaults.topAppBarColors()`.
|
|
35
|
+
*/
|
|
36
|
+
colors?: TopAppBarColors;
|
|
37
|
+
/**
|
|
38
|
+
* Insets in dp that the app bar adds around its content. Missing sides are `0`.
|
|
39
|
+
* When omitted, the app bar uses `TopAppBarDefaults.windowInsets`, which assumes
|
|
40
|
+
* the bar is at the top edge of the window, even inside a nested `Host`.
|
|
41
|
+
* Pass `{}` when a parent handles the insets. This removes both the top status
|
|
42
|
+
* bar inset and the horizontal system bar and display cutout insets.
|
|
43
|
+
*/
|
|
44
|
+
windowInsets?: PaddingValuesRecord;
|
|
45
|
+
/**
|
|
46
|
+
* Modifiers for the component.
|
|
47
|
+
*/
|
|
48
|
+
modifiers?: ExpoModifier[];
|
|
49
|
+
/**
|
|
50
|
+
* `TopAppBar.Title`, `TopAppBar.NavigationIcon`, and `TopAppBar.Actions` slots.
|
|
51
|
+
*/
|
|
52
|
+
children: React.ReactNode;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
type SlotProps = {
|
|
56
|
+
children: React.ReactNode;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
type NativeSlotViewProps = {
|
|
60
|
+
slotName: string;
|
|
61
|
+
children: React.ReactNode;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
const TopAppBarNativeView: React.ComponentType<TopAppBarProps> = requireNativeView(
|
|
65
|
+
'ExpoUI',
|
|
66
|
+
'TopAppBarView'
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
const SlotNativeView: React.ComponentType<NativeSlotViewProps> = requireNativeView(
|
|
70
|
+
'ExpoUI',
|
|
71
|
+
'SlotView'
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Title slot for `TopAppBar`.
|
|
76
|
+
*/
|
|
77
|
+
function TopAppBarTitle(props: SlotProps) {
|
|
78
|
+
return <SlotNativeView slotName="title">{props.children}</SlotNativeView>;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Navigation icon slot for `TopAppBar`. It appears at the start of the app bar.
|
|
83
|
+
*/
|
|
84
|
+
function TopAppBarNavigationIcon(props: SlotProps) {
|
|
85
|
+
return <SlotNativeView slotName="navigationIcon">{props.children}</SlotNativeView>;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Actions slot for `TopAppBar`. Its children appear in a row at the end of the app bar.
|
|
90
|
+
*/
|
|
91
|
+
function TopAppBarActions(props: SlotProps) {
|
|
92
|
+
return <SlotNativeView slotName="actions">{props.children}</SlotNativeView>;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* A Material 3 small top app bar that shows a title, a navigation icon, and actions.
|
|
97
|
+
*/
|
|
98
|
+
function TopAppBar(props: TopAppBarProps) {
|
|
99
|
+
const { modifiers, ...restProps } = props;
|
|
100
|
+
return (
|
|
101
|
+
<TopAppBarNativeView
|
|
102
|
+
modifiers={modifiers}
|
|
103
|
+
{...(modifiers ? createViewModifierEventListener(modifiers) : undefined)}
|
|
104
|
+
{...restProps}
|
|
105
|
+
/>
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
TopAppBar.Title = TopAppBarTitle;
|
|
110
|
+
TopAppBar.NavigationIcon = TopAppBarNavigationIcon;
|
|
111
|
+
TopAppBar.Actions = TopAppBarActions;
|
|
112
|
+
|
|
113
|
+
export { TopAppBar };
|
|
@@ -59,6 +59,7 @@ export * from './SearchBar';
|
|
|
59
59
|
export * from './Snackbar';
|
|
60
60
|
export * from './DockedSearchBar';
|
|
61
61
|
export * from './HorizontalFloatingToolbar';
|
|
62
|
+
export * from './TopAppBar';
|
|
62
63
|
export * from './FloatingActionButton';
|
|
63
64
|
export * from './PullToRefreshBox';
|
|
64
65
|
export * from './RadioButton';
|
|
@@ -71,6 +72,7 @@ export * from './AnimatedVisibility';
|
|
|
71
72
|
export * from './Box';
|
|
72
73
|
export * from './Row';
|
|
73
74
|
export * from './Column';
|
|
75
|
+
export * from './CompositionLocalProvider';
|
|
74
76
|
export * from './FlowRow';
|
|
75
77
|
export { useNativeState, useWorkletCallback, type WorkletCallback } from '../State';
|
|
76
78
|
export type { ViewEvent } from '../types';
|
|
@@ -403,13 +403,21 @@ export const selectableGroup = () => createModifier('selectableGroup');
|
|
|
403
403
|
* @param value - The current toggle state.
|
|
404
404
|
* @param handler - Function to call when toggled.
|
|
405
405
|
* @param options - Optional configuration.
|
|
406
|
-
* @param options.role - The semantic role for accessibility: `'checkbox'`, `'radioButton'`,
|
|
406
|
+
* @param options.role - The semantic role for accessibility: `'checkbox'`, `'radioButton'`,
|
|
407
|
+
* `'switch'`, or `'tab'`.
|
|
408
|
+
* @param options.enabled - Whether the view responds to input and is reported as enabled to
|
|
409
|
+
* accessibility services. Defaults to `true`.
|
|
407
410
|
*/
|
|
408
411
|
export const toggleable = (
|
|
409
412
|
value: boolean,
|
|
410
413
|
handler: () => void,
|
|
411
|
-
options?: { role?: 'checkbox' | 'radioButton' | 'switch' | 'tab' }
|
|
412
|
-
) =>
|
|
414
|
+
options?: { role?: 'checkbox' | 'radioButton' | 'switch' | 'tab'; enabled?: boolean }
|
|
415
|
+
) =>
|
|
416
|
+
createModifierWithEventListener('toggleable', handler, {
|
|
417
|
+
value,
|
|
418
|
+
role: options?.role,
|
|
419
|
+
enabled: options?.enabled,
|
|
420
|
+
});
|
|
413
421
|
|
|
414
422
|
// =============================================================================
|
|
415
423
|
// Lifecycle Modifiers
|
|
@@ -18,6 +18,12 @@ export interface BottomSheetProps extends CommonViewModifierProps {
|
|
|
18
18
|
* kept mounted, so presenting the sheet doesn't shift surrounding layout. Optional.
|
|
19
19
|
*/
|
|
20
20
|
anchor?: ReactNode;
|
|
21
|
+
/**
|
|
22
|
+
* A view that fills the whole sheet behind its content, for example a `Rectangle` filled with a
|
|
23
|
+
* material. Unlike the `presentationBackground` modifier, a material in a view stays translucent
|
|
24
|
+
* on iOS 26 and later.
|
|
25
|
+
*/
|
|
26
|
+
presentationBackground?: ReactNode;
|
|
21
27
|
/**
|
|
22
28
|
* Whether the `BottomSheet` is presented.
|
|
23
29
|
*/
|
|
@@ -40,7 +46,7 @@ export interface BottomSheetProps extends CommonViewModifierProps {
|
|
|
40
46
|
|
|
41
47
|
type NativeBottomSheetProps = Omit<
|
|
42
48
|
BottomSheetProps,
|
|
43
|
-
'onIsPresentedChange' | 'onDismiss' | 'anchor'
|
|
49
|
+
'onIsPresentedChange' | 'onDismiss' | 'anchor' | 'presentationBackground'
|
|
44
50
|
> & {
|
|
45
51
|
onIsPresentedChange: (event: NativeSyntheticEvent<{ isPresented: boolean }>) => void;
|
|
46
52
|
onDismiss: (event: NativeSyntheticEvent<object>) => void;
|
|
@@ -55,7 +61,15 @@ const BottomSheetNativeView: ComponentType<NativeBottomSheetProps> = requireNati
|
|
|
55
61
|
* `BottomSheet` presents content from the bottom of the screen.
|
|
56
62
|
*/
|
|
57
63
|
function BottomSheet(props: BottomSheetProps) {
|
|
58
|
-
const {
|
|
64
|
+
const {
|
|
65
|
+
modifiers,
|
|
66
|
+
onIsPresentedChange,
|
|
67
|
+
onDismiss,
|
|
68
|
+
anchor,
|
|
69
|
+
presentationBackground,
|
|
70
|
+
children,
|
|
71
|
+
...restProps
|
|
72
|
+
} = props;
|
|
59
73
|
const [isMounted, setIsMounted] = useState(props.isPresented);
|
|
60
74
|
|
|
61
75
|
if (props.isPresented && !isMounted) {
|
|
@@ -79,7 +93,14 @@ function BottomSheet(props: BottomSheetProps) {
|
|
|
79
93
|
{anchor != null ? <Slot name="anchor">{anchor}</Slot> : null}
|
|
80
94
|
{/* Only the sheet's content is presented in its own view controller. The anchor renders in
|
|
81
95
|
place, in the React Native surface, so it stays outside `PresentedContent`. */}
|
|
82
|
-
{isMounted ?
|
|
96
|
+
{isMounted ? (
|
|
97
|
+
<PresentedContent>
|
|
98
|
+
{presentationBackground != null ? (
|
|
99
|
+
<Slot name="presentationBackground">{presentationBackground}</Slot>
|
|
100
|
+
) : null}
|
|
101
|
+
{children}
|
|
102
|
+
</PresentedContent>
|
|
103
|
+
) : null}
|
|
83
104
|
</BottomSheetNativeView>
|
|
84
105
|
);
|
|
85
106
|
}
|