@expo/ui 56.0.2 → 56.0.4
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 +11 -0
- package/android/build.gradle +2 -2
- package/android/src/main/java/expo/modules/ui/ExpoUIModule.kt +6 -0
- package/android/src/main/java/expo/modules/ui/MaskView.kt +56 -0
- package/build/community/masked-view/MaskedView.android.d.ts +8 -0
- package/build/community/masked-view/MaskedView.android.d.ts.map +1 -0
- package/build/community/masked-view/MaskedView.d.ts +10 -0
- package/build/community/masked-view/MaskedView.d.ts.map +1 -0
- package/build/community/masked-view/MaskedView.ios.d.ts +8 -0
- package/build/community/masked-view/MaskedView.ios.d.ts.map +1 -0
- package/build/community/masked-view/index.d.ts +4 -0
- package/build/community/masked-view/index.d.ts.map +1 -0
- package/build/community/masked-view/types.d.ts +19 -0
- package/build/community/masked-view/types.d.ts.map +1 -0
- package/build/community/picker/Picker.android.d.ts +10 -2
- package/build/community/picker/Picker.android.d.ts.map +1 -1
- package/build/community/picker/Picker.d.ts +10 -2
- package/build/community/picker/Picker.d.ts.map +1 -1
- package/build/community/picker/Picker.ios.d.ts +10 -2
- package/build/community/picker/Picker.ios.d.ts.map +1 -1
- package/build/community/picker/types.d.ts +12 -10
- package/build/community/picker/types.d.ts.map +1 -1
- package/build/jetpack-compose/modifiers/index.d.ts +1 -1
- package/build/universal/Button/index.d.ts.map +1 -1
- package/build/universal/Checkbox/index.d.ts.map +1 -1
- package/build/universal/Column/index.d.ts.map +1 -1
- package/build/universal/FieldGroup/FieldGroup.d.ts.map +1 -1
- package/build/universal/FieldGroup/FieldSection.d.ts.map +1 -1
- package/build/universal/Row/index.d.ts.map +1 -1
- package/build/universal/ScrollView/index.d.ts.map +1 -1
- package/build/universal/Slider/index.d.ts.map +1 -1
- package/build/universal/Spacer/index.d.ts.map +1 -1
- package/build/universal/Switch/index.d.ts.map +1 -1
- package/build/universal/Text/index.d.ts.map +1 -1
- package/expo-module.config.json +1 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/{56.0.2/expo.modules.ui-56.0.2-sources.jar → 56.0.4/expo.modules.ui-56.0.4-sources.jar} +0 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.4/expo.modules.ui-56.0.4-sources.jar.md5 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.4/expo.modules.ui-56.0.4-sources.jar.sha1 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.4/expo.modules.ui-56.0.4-sources.jar.sha256 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.4/expo.modules.ui-56.0.4-sources.jar.sha512 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.4/expo.modules.ui-56.0.4.aar +0 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.4/expo.modules.ui-56.0.4.aar.md5 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.4/expo.modules.ui-56.0.4.aar.sha1 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.4/expo.modules.ui-56.0.4.aar.sha256 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.4/expo.modules.ui-56.0.4.aar.sha512 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/{56.0.2/expo.modules.ui-56.0.2.module → 56.0.4/expo.modules.ui-56.0.4.module} +23 -23
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.4/expo.modules.ui-56.0.4.module.md5 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.4/expo.modules.ui-56.0.4.module.sha1 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.4/expo.modules.ui-56.0.4.module.sha256 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.4/expo.modules.ui-56.0.4.module.sha512 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/{56.0.2/expo.modules.ui-56.0.2.pom → 56.0.4/expo.modules.ui-56.0.4.pom} +2 -2
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.4/expo.modules.ui-56.0.4.pom.md5 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.4/expo.modules.ui-56.0.4.pom.sha1 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.4/expo.modules.ui-56.0.4.pom.sha256 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.4/expo.modules.ui-56.0.4.pom.sha512 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/maven-metadata.xml +4 -4
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/maven-metadata.xml.md5 +1 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/maven-metadata.xml.sha1 +1 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/maven-metadata.xml.sha256 +1 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/maven-metadata.xml.sha512 +1 -1
- package/package.json +8 -4
- package/src/community/masked-view/MaskedView.android.tsx +40 -0
- package/src/community/masked-view/MaskedView.ios.tsx +32 -0
- package/src/community/masked-view/MaskedView.tsx +34 -0
- package/src/community/masked-view/index.tsx +3 -0
- package/src/community/masked-view/types.ts +19 -0
- package/src/community/picker/Picker.android.tsx +12 -5
- package/src/community/picker/Picker.ios.tsx +9 -6
- package/src/community/picker/Picker.tsx +3 -4
- package/src/community/picker/types.tsx +24 -18
- package/src/jetpack-compose/modifiers/index.ts +1 -1
- package/src/ts-declarations/react-native-web.d.ts +112 -0
- package/src/universal/Button/index.tsx +37 -50
- package/src/universal/Checkbox/index.tsx +31 -18
- package/src/universal/Column/index.tsx +29 -18
- package/src/universal/FieldGroup/FieldGroup.tsx +24 -28
- package/src/universal/FieldGroup/FieldSection.tsx +62 -80
- package/src/universal/Row/index.tsx +37 -24
- package/src/universal/ScrollView/index.tsx +26 -15
- package/src/universal/Slider/index.tsx +21 -16
- package/src/universal/Spacer/index.tsx +18 -10
- package/src/universal/Switch/index.tsx +15 -10
- package/src/universal/Text/index.tsx +18 -37
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.2/expo.modules.ui-56.0.2-sources.jar.md5 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.2/expo.modules.ui-56.0.2-sources.jar.sha1 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.2/expo.modules.ui-56.0.2-sources.jar.sha256 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.2/expo.modules.ui-56.0.2-sources.jar.sha512 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.2/expo.modules.ui-56.0.2.aar +0 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.2/expo.modules.ui-56.0.2.aar.md5 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.2/expo.modules.ui-56.0.2.aar.sha1 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.2/expo.modules.ui-56.0.2.aar.sha256 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.2/expo.modules.ui-56.0.2.aar.sha512 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.2/expo.modules.ui-56.0.2.module.md5 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.2/expo.modules.ui-56.0.2.module.sha1 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.2/expo.modules.ui-56.0.2.module.sha256 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.2/expo.modules.ui-56.0.2.module.sha512 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.2/expo.modules.ui-56.0.2.pom.md5 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.2/expo.modules.ui-56.0.2.pom.sha1 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.2/expo.modules.ui-56.0.2.pom.sha256 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.2/expo.modules.ui-56.0.2.pom.sha512 +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@expo/ui",
|
|
3
|
-
"version": "56.0.
|
|
3
|
+
"version": "56.0.4",
|
|
4
4
|
"description": "A collection of UI components",
|
|
5
5
|
"sideEffects": [
|
|
6
6
|
"*.fx.js"
|
|
@@ -43,6 +43,10 @@
|
|
|
43
43
|
"types": "./build/community/picker/index.d.ts",
|
|
44
44
|
"default": "./src/community/picker/index.tsx"
|
|
45
45
|
},
|
|
46
|
+
"./community/masked-view": {
|
|
47
|
+
"types": "./build/community/masked-view/index.d.ts",
|
|
48
|
+
"default": "./src/community/masked-view/index.tsx"
|
|
49
|
+
},
|
|
46
50
|
"./babel-plugin": {
|
|
47
51
|
"types": "./plugin/babel-plugin.d.ts",
|
|
48
52
|
"default": "./plugin/babel-plugin.js"
|
|
@@ -79,8 +83,8 @@
|
|
|
79
83
|
"@types/react": "~19.2.0",
|
|
80
84
|
"react-native-reanimated": "4.3.0",
|
|
81
85
|
"react-native-worklets": "0.8.3",
|
|
82
|
-
"expo": "56.0.0-preview.
|
|
83
|
-
"expo-module-scripts": "56.0.
|
|
86
|
+
"expo": "56.0.0-preview.7",
|
|
87
|
+
"expo-module-scripts": "56.0.2"
|
|
84
88
|
},
|
|
85
89
|
"jest": {
|
|
86
90
|
"preset": "expo-module-scripts"
|
|
@@ -108,7 +112,7 @@
|
|
|
108
112
|
"optional": true
|
|
109
113
|
}
|
|
110
114
|
},
|
|
111
|
-
"gitHead": "
|
|
115
|
+
"gitHead": "a30353e69ca0d72b9fac5830abc631feda1ba3ae",
|
|
112
116
|
"scripts": {
|
|
113
117
|
"build": "expo-module build",
|
|
114
118
|
"clean": "expo-module clean",
|
|
@@ -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,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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
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
|
}
|
|
@@ -142,7 +142,7 @@ export const offset = (x: number, y: number) => createModifier('offset', { x, y
|
|
|
142
142
|
|
|
143
143
|
/**
|
|
144
144
|
* Sets the background color.
|
|
145
|
-
* @param color -
|
|
145
|
+
* @param color - A color string (hex, e.g., `'#FF0000'`).
|
|
146
146
|
*/
|
|
147
147
|
export const background = (color: ColorValue) => createModifier('background', { color });
|
|
148
148
|
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import * as ReactNative from 'react-native';
|
|
2
|
+
|
|
3
|
+
declare module 'react-native' {
|
|
4
|
+
export const unstable_createElement: <P>(
|
|
5
|
+
type: React.ElementType,
|
|
6
|
+
props?: P
|
|
7
|
+
) => React.ReactElement<P>;
|
|
8
|
+
|
|
9
|
+
type DisplayValue = ReactNative.FlexStyle['display'] | 'inline-flex';
|
|
10
|
+
|
|
11
|
+
type WebRole =
|
|
12
|
+
| ReactNative.Role
|
|
13
|
+
/**
|
|
14
|
+
* Accessibility roles mapped to components
|
|
15
|
+
* @see https://github.com/necolas/react-native-web/blob/0.19.1/packages/react-native-web/src/modules/AccessibilityUtil/propsToAccessibilityComponent.js
|
|
16
|
+
*/
|
|
17
|
+
| 'article' // <article />
|
|
18
|
+
| 'banner' // <header />
|
|
19
|
+
| 'blockquote' // <blockquote />
|
|
20
|
+
| 'button' // <button />
|
|
21
|
+
| 'code' // <code />
|
|
22
|
+
| 'complementary' // <aside />
|
|
23
|
+
| 'contentinfo' // <footer />
|
|
24
|
+
| 'deletion' // <del />
|
|
25
|
+
| 'emphasis' // <em />
|
|
26
|
+
| 'figure' // <figure />
|
|
27
|
+
| 'form' // <form />
|
|
28
|
+
| 'heading' // <h{1,6} />
|
|
29
|
+
| 'insertion' // <ins />
|
|
30
|
+
| 'label' // <label />
|
|
31
|
+
| 'list' // <ul />
|
|
32
|
+
| 'listitem' // <li />
|
|
33
|
+
| 'main' // <main />
|
|
34
|
+
| 'navigation' // <nav />
|
|
35
|
+
| 'paragraph' // <p />
|
|
36
|
+
| 'region' // <section />
|
|
37
|
+
| 'strong'; // <strong />
|
|
38
|
+
|
|
39
|
+
interface WebAccessibilityProps {
|
|
40
|
+
/**
|
|
41
|
+
* Additional accessibility props
|
|
42
|
+
*/
|
|
43
|
+
tabIndex?: 0 | -1;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Aria props (additional, minus existants)
|
|
47
|
+
* @see https://necolas.github.io/react-native-web/docs/accessibility
|
|
48
|
+
* @see https://reactnative.dev/docs/accessibility#aria-valuemax
|
|
49
|
+
*/
|
|
50
|
+
'aria-activedescendant'?: string;
|
|
51
|
+
'aria-atomic'?: boolean;
|
|
52
|
+
'aria-autocomplete'?: string;
|
|
53
|
+
'aria-colcount'?: number;
|
|
54
|
+
'aria-colindex'?: number;
|
|
55
|
+
'aria-colspan'?: number;
|
|
56
|
+
'aria-controls'?: string;
|
|
57
|
+
'aria-current'?: boolean | 'page' | 'step' | 'location' | 'date' | 'time';
|
|
58
|
+
'aria-describedby'?: string;
|
|
59
|
+
'aria-details'?: string;
|
|
60
|
+
'aria-errormessage'?: string;
|
|
61
|
+
'aria-flowto'?: string;
|
|
62
|
+
'aria-haspopup'?: string;
|
|
63
|
+
'aria-invalid'?: boolean;
|
|
64
|
+
'aria-keyshortcuts'?: string;
|
|
65
|
+
'aria-level'?: number;
|
|
66
|
+
'aria-multiline'?: boolean;
|
|
67
|
+
'aria-multiselectable'?: boolean;
|
|
68
|
+
'aria-orientation'?: 'horizontal' | 'vertical';
|
|
69
|
+
'aria-owns'?: string;
|
|
70
|
+
'aria-placeholder'?: string;
|
|
71
|
+
'aria-posinset'?: number;
|
|
72
|
+
'aria-pressed'?: boolean;
|
|
73
|
+
'aria-readonly'?: boolean;
|
|
74
|
+
'aria-required'?: boolean;
|
|
75
|
+
'aria-roledescription'?: string;
|
|
76
|
+
'aria-rowcount'?: number;
|
|
77
|
+
'aria-rowindex'?: number;
|
|
78
|
+
'aria-rowspan'?: number;
|
|
79
|
+
'aria-setsize'?: number;
|
|
80
|
+
'aria-sort'?: 'ascending' | 'descending' | 'none' | 'other';
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export interface PressableStateCallbackType {
|
|
84
|
+
readonly focused: boolean;
|
|
85
|
+
readonly hovered: boolean;
|
|
86
|
+
readonly pressed: boolean;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export interface ImageProps extends WebAccessibilityProps {
|
|
90
|
+
role?: WebRole;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export interface TextProps extends WebAccessibilityProps {
|
|
94
|
+
role?: WebRole;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export interface ViewProps extends WebAccessibilityProps {
|
|
98
|
+
role?: WebRole;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export interface ImageStyle {
|
|
102
|
+
display?: DisplayValue;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export interface TextStyle {
|
|
106
|
+
display?: DisplayValue;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export interface ViewStyle {
|
|
110
|
+
display?: DisplayValue;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
@@ -1,48 +1,40 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { Pressable, Text, type ViewStyle } from 'react-native';
|
|
1
|
+
import { Pressable, StyleSheet, Text, type TextStyle, type ViewStyle } from 'react-native';
|
|
3
2
|
|
|
4
3
|
import type { ButtonProps, ButtonVariant } from './types';
|
|
5
4
|
import { useUniversalLifecycle } from '../hooks';
|
|
6
5
|
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
backgroundColor: '#007AFF',
|
|
6
|
+
const styles = StyleSheet.create({
|
|
7
|
+
button: {
|
|
10
8
|
paddingHorizontal: 16,
|
|
11
9
|
paddingVertical: 10,
|
|
12
10
|
borderRadius: 8,
|
|
11
|
+
userSelect: 'none',
|
|
13
12
|
},
|
|
13
|
+
disabled: { opacity: 0.5 },
|
|
14
|
+
hidden: { display: 'none' },
|
|
15
|
+
label: { textAlign: 'center' },
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
const variantStyles = StyleSheet.create({
|
|
19
|
+
filled: { backgroundColor: '#007AFF' },
|
|
14
20
|
outlined: {
|
|
15
|
-
backgroundColor: 'transparent',
|
|
16
|
-
paddingHorizontal: 16,
|
|
17
|
-
paddingVertical: 10,
|
|
18
|
-
borderRadius: 8,
|
|
19
|
-
borderWidth: 1,
|
|
20
21
|
borderColor: '#007AFF',
|
|
22
|
+
borderWidth: 1,
|
|
21
23
|
},
|
|
22
|
-
text: {
|
|
23
|
-
|
|
24
|
-
paddingHorizontal: 16,
|
|
25
|
-
paddingVertical: 10,
|
|
26
|
-
},
|
|
27
|
-
};
|
|
24
|
+
text: {},
|
|
25
|
+
} satisfies Record<ButtonVariant, ViewStyle>);
|
|
28
26
|
|
|
29
|
-
const variantHoverStyles
|
|
30
|
-
filled: {
|
|
31
|
-
|
|
32
|
-
},
|
|
33
|
-
|
|
34
|
-
backgroundColor: 'rgba(0, 122, 255, 0.08)',
|
|
35
|
-
},
|
|
36
|
-
text: {
|
|
37
|
-
backgroundColor: 'rgba(0, 122, 255, 0.08)',
|
|
38
|
-
},
|
|
39
|
-
};
|
|
27
|
+
const variantHoverStyles = StyleSheet.create({
|
|
28
|
+
filled: { backgroundColor: '#0066DB' },
|
|
29
|
+
outlined: { backgroundColor: 'rgba(0, 122, 255, 0.08)' },
|
|
30
|
+
text: { backgroundColor: 'rgba(0, 122, 255, 0.08)' },
|
|
31
|
+
} satisfies Record<ButtonVariant, ViewStyle>);
|
|
40
32
|
|
|
41
|
-
const
|
|
42
|
-
filled: '#FFFFFF',
|
|
43
|
-
outlined: '#007AFF',
|
|
44
|
-
text: '#007AFF',
|
|
45
|
-
};
|
|
33
|
+
const variantLabelStyles = StyleSheet.create({
|
|
34
|
+
filled: { color: '#FFFFFF' },
|
|
35
|
+
outlined: { color: '#007AFF' },
|
|
36
|
+
text: { color: '#007AFF' },
|
|
37
|
+
} satisfies Record<ButtonVariant, TextStyle>);
|
|
46
38
|
|
|
47
39
|
/**
|
|
48
40
|
* A pressable button that supports multiple visual variants.
|
|
@@ -55,32 +47,27 @@ export function Button({
|
|
|
55
47
|
style,
|
|
56
48
|
onAppear,
|
|
57
49
|
onDisappear,
|
|
58
|
-
disabled,
|
|
59
|
-
hidden,
|
|
50
|
+
disabled = false,
|
|
51
|
+
hidden = false,
|
|
60
52
|
testID,
|
|
61
53
|
}: ButtonProps) {
|
|
62
54
|
useUniversalLifecycle(onAppear, onDisappear);
|
|
63
|
-
const [hovered, setHovered] = useState(false);
|
|
64
|
-
|
|
65
|
-
const pressableStyle: ViewStyle = {
|
|
66
|
-
...variantStyles[variant],
|
|
67
|
-
...style,
|
|
68
|
-
...(hovered && !disabled ? variantHoverStyles[variant] : undefined),
|
|
69
|
-
...(hidden ? { display: 'none' } : undefined),
|
|
70
|
-
...(disabled ? { opacity: 0.5 } : undefined),
|
|
71
|
-
};
|
|
72
55
|
|
|
73
56
|
return (
|
|
74
57
|
<Pressable
|
|
75
|
-
|
|
58
|
+
role="button"
|
|
76
59
|
onPress={onPress}
|
|
77
|
-
onHoverIn={() => setHovered(true)}
|
|
78
|
-
onHoverOut={() => setHovered(false)}
|
|
79
60
|
disabled={disabled}
|
|
80
|
-
testID={testID}
|
|
81
|
-
{
|
|
82
|
-
|
|
83
|
-
|
|
61
|
+
testID={testID}
|
|
62
|
+
style={({ hovered }) => [
|
|
63
|
+
styles.button,
|
|
64
|
+
variantStyles[variant],
|
|
65
|
+
style,
|
|
66
|
+
hovered && !disabled && variantHoverStyles[variant],
|
|
67
|
+
hidden && styles.hidden,
|
|
68
|
+
disabled && styles.disabled,
|
|
69
|
+
]}>
|
|
70
|
+
{children ?? <Text style={[styles.label, variantLabelStyles[variant]]}>{label}</Text>}
|
|
84
71
|
</Pressable>
|
|
85
72
|
);
|
|
86
73
|
}
|
|
@@ -1,33 +1,46 @@
|
|
|
1
|
+
import type { ComponentProps } from 'react';
|
|
2
|
+
import { StyleSheet, Text, unstable_createElement, View, type ViewProps } from 'react-native';
|
|
3
|
+
|
|
1
4
|
import type { CheckboxProps } from './types';
|
|
2
5
|
|
|
6
|
+
const styles = StyleSheet.create({
|
|
7
|
+
label: {
|
|
8
|
+
flexDirection: 'row',
|
|
9
|
+
display: 'inline-flex',
|
|
10
|
+
alignItems: 'center',
|
|
11
|
+
gap: 8,
|
|
12
|
+
cursor: 'pointer',
|
|
13
|
+
},
|
|
14
|
+
disabled: {
|
|
15
|
+
opacity: 0.5,
|
|
16
|
+
cursor: 'auto',
|
|
17
|
+
},
|
|
18
|
+
cursorInherit: {
|
|
19
|
+
// @ts-expect-error
|
|
20
|
+
cursor: 'inherit',
|
|
21
|
+
},
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
const NativeCheckbox = (
|
|
25
|
+
props: Omit<ComponentProps<'input'>, 'style' | 'type'> & { style?: ViewProps['style'] }
|
|
26
|
+
) => unstable_createElement('input', { ...props, type: 'checkbox' });
|
|
27
|
+
|
|
3
28
|
/**
|
|
4
29
|
* A toggle control that represents a checked or unchecked state.
|
|
5
30
|
*/
|
|
6
|
-
export function Checkbox({ value, onValueChange, label, disabled, testID }: CheckboxProps) {
|
|
31
|
+
export function Checkbox({ value, onValueChange, label, disabled = false, testID }: CheckboxProps) {
|
|
7
32
|
return (
|
|
8
|
-
<label style={
|
|
9
|
-
<
|
|
10
|
-
type="checkbox"
|
|
33
|
+
<View role="label" aria-disabled={disabled} style={[styles.label, disabled && styles.disabled]}>
|
|
34
|
+
<NativeCheckbox
|
|
11
35
|
checked={value}
|
|
12
36
|
onChange={(e) => onValueChange(e.target.checked)}
|
|
13
37
|
disabled={disabled}
|
|
14
38
|
data-testid={testID}
|
|
39
|
+
style={styles.cursorInherit}
|
|
15
40
|
/>
|
|
16
|
-
{label != null && <
|
|
17
|
-
</
|
|
41
|
+
{label != null && <Text>{label}</Text>}
|
|
42
|
+
</View>
|
|
18
43
|
);
|
|
19
44
|
}
|
|
20
45
|
|
|
21
|
-
const labelStyle: React.CSSProperties = {
|
|
22
|
-
display: 'inline-flex',
|
|
23
|
-
alignItems: 'center',
|
|
24
|
-
gap: 8,
|
|
25
|
-
cursor: 'pointer',
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
const disabledStyle: React.CSSProperties = {
|
|
29
|
-
opacity: 0.5,
|
|
30
|
-
cursor: 'default',
|
|
31
|
-
};
|
|
32
|
-
|
|
33
46
|
export * from './types';
|