@expo/ui 56.0.3 → 56.0.5
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 +16 -0
- package/android/build.gradle +2 -2
- package/build/swift-ui/ScrollView/index.d.ts +3 -2
- package/build/swift-ui/ScrollView/index.d.ts.map +1 -1
- package/build/swift-ui/modifiers/index.d.ts +15 -1
- package/build/swift-ui/modifiers/index.d.ts.map +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/ios/Convertibles/AxisOptions.swift +19 -0
- package/ios/Convertibles/ScrollIndicatorVisibilityOptions.swift +22 -0
- package/ios/Modifiers/ContainerRelativeFrameModifier.swift +1 -18
- package/ios/Modifiers/ScrollIndicatorsModifier.swift +13 -0
- package/ios/Modifiers/ViewModifierRegistry.swift +4 -17
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/{56.0.3/expo.modules.ui-56.0.3.module → 56.0.5/expo.modules.ui-56.0.5.module} +7 -7
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.5/expo.modules.ui-56.0.5.module.md5 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.5/expo.modules.ui-56.0.5.module.sha1 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.5/expo.modules.ui-56.0.5.module.sha256 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.5/expo.modules.ui-56.0.5.module.sha512 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/{56.0.3/expo.modules.ui-56.0.3.pom → 56.0.5/expo.modules.ui-56.0.5.pom} +1 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.5/expo.modules.ui-56.0.5.pom.md5 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.5/expo.modules.ui-56.0.5.pom.sha1 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.5/expo.modules.ui-56.0.5.pom.sha256 +1 -0
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.5/expo.modules.ui-56.0.5.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 +4 -4
- package/src/swift-ui/ScrollView/index.tsx +3 -2
- package/src/swift-ui/modifiers/index.ts +19 -0
- 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.3/expo.modules.ui-56.0.3.module.md5 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.3/expo.modules.ui-56.0.3.module.sha1 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.3/expo.modules.ui-56.0.3.module.sha256 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.3/expo.modules.ui-56.0.3.module.sha512 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.3/expo.modules.ui-56.0.3.pom.md5 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.3/expo.modules.ui-56.0.3.pom.sha1 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.3/expo.modules.ui-56.0.3.pom.sha256 +0 -1
- package/local-maven-repo/expo/modules/ui/expo.modules.ui/56.0.3/expo.modules.ui-56.0.3.pom.sha512 +0 -1
- /package/local-maven-repo/expo/modules/ui/expo.modules.ui/{56.0.3/expo.modules.ui-56.0.3-sources.jar → 56.0.5/expo.modules.ui-56.0.5-sources.jar} +0 -0
- /package/local-maven-repo/expo/modules/ui/expo.modules.ui/{56.0.3/expo.modules.ui-56.0.3-sources.jar.md5 → 56.0.5/expo.modules.ui-56.0.5-sources.jar.md5} +0 -0
- /package/local-maven-repo/expo/modules/ui/expo.modules.ui/{56.0.3/expo.modules.ui-56.0.3-sources.jar.sha1 → 56.0.5/expo.modules.ui-56.0.5-sources.jar.sha1} +0 -0
- /package/local-maven-repo/expo/modules/ui/expo.modules.ui/{56.0.3/expo.modules.ui-56.0.3-sources.jar.sha256 → 56.0.5/expo.modules.ui-56.0.5-sources.jar.sha256} +0 -0
- /package/local-maven-repo/expo/modules/ui/expo.modules.ui/{56.0.3/expo.modules.ui-56.0.3-sources.jar.sha512 → 56.0.5/expo.modules.ui-56.0.5-sources.jar.sha512} +0 -0
- /package/local-maven-repo/expo/modules/ui/expo.modules.ui/{56.0.3/expo.modules.ui-56.0.3.aar → 56.0.5/expo.modules.ui-56.0.5.aar} +0 -0
- /package/local-maven-repo/expo/modules/ui/expo.modules.ui/{56.0.3/expo.modules.ui-56.0.3.aar.md5 → 56.0.5/expo.modules.ui-56.0.5.aar.md5} +0 -0
- /package/local-maven-repo/expo/modules/ui/expo.modules.ui/{56.0.3/expo.modules.ui-56.0.3.aar.sha1 → 56.0.5/expo.modules.ui-56.0.5.aar.sha1} +0 -0
- /package/local-maven-repo/expo/modules/ui/expo.modules.ui/{56.0.3/expo.modules.ui-56.0.3.aar.sha256 → 56.0.5/expo.modules.ui-56.0.5.aar.sha256} +0 -0
- /package/local-maven-repo/expo/modules/ui/expo.modules.ui/{56.0.3/expo.modules.ui-56.0.3.aar.sha512 → 56.0.5/expo.modules.ui-56.0.5.aar.sha512} +0 -0
|
@@ -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';
|
|
@@ -1,14 +1,23 @@
|
|
|
1
|
-
import { Pressable, View, type ViewStyle } from 'react-native';
|
|
1
|
+
import { Pressable, StyleSheet, View, type ViewStyle } from 'react-native';
|
|
2
2
|
|
|
3
3
|
import type { ColumnProps } from './types';
|
|
4
4
|
import { useUniversalLifecycle } from '../hooks';
|
|
5
5
|
import type { UniversalAlignment } from '../types';
|
|
6
6
|
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
const styles = StyleSheet.create({
|
|
8
|
+
column: { flexDirection: 'column' },
|
|
9
|
+
hidden: { display: 'none' },
|
|
10
|
+
disabled: {
|
|
11
|
+
opacity: 0.5,
|
|
12
|
+
pointerEvents: 'none',
|
|
13
|
+
},
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
const alignmentStyles = StyleSheet.create({
|
|
17
|
+
start: { alignItems: 'flex-start' },
|
|
18
|
+
center: { alignItems: 'center' },
|
|
19
|
+
end: { alignItems: 'flex-end' },
|
|
20
|
+
} satisfies Record<UniversalAlignment, ViewStyle>);
|
|
12
21
|
|
|
13
22
|
/**
|
|
14
23
|
* A vertical layout container that arranges its children from top to bottom.
|
|
@@ -21,25 +30,27 @@ export function Column({
|
|
|
21
30
|
onPress,
|
|
22
31
|
onAppear,
|
|
23
32
|
onDisappear,
|
|
24
|
-
disabled,
|
|
25
|
-
hidden,
|
|
33
|
+
disabled = false,
|
|
34
|
+
hidden = false,
|
|
26
35
|
testID,
|
|
27
36
|
}: ColumnProps) {
|
|
28
37
|
useUniversalLifecycle(onAppear, onDisappear);
|
|
29
38
|
|
|
30
|
-
const viewStyle: ViewStyle = {
|
|
31
|
-
flexDirection: 'column',
|
|
32
|
-
alignItems: alignmentMap[alignment],
|
|
33
|
-
gap: spacing,
|
|
34
|
-
...style,
|
|
35
|
-
...(hidden ? { display: 'none' } : undefined),
|
|
36
|
-
...(disabled ? { opacity: 0.5, pointerEvents: 'none' } : undefined),
|
|
37
|
-
};
|
|
38
|
-
|
|
39
39
|
const Container = onPress ? Pressable : View;
|
|
40
40
|
|
|
41
41
|
return (
|
|
42
|
-
<Container
|
|
42
|
+
<Container
|
|
43
|
+
onPress={onPress}
|
|
44
|
+
disabled={disabled}
|
|
45
|
+
testID={testID}
|
|
46
|
+
style={[
|
|
47
|
+
styles.column,
|
|
48
|
+
alignmentStyles[alignment],
|
|
49
|
+
spacing != null && { gap: spacing },
|
|
50
|
+
style,
|
|
51
|
+
hidden && styles.hidden,
|
|
52
|
+
disabled && styles.disabled,
|
|
53
|
+
]}>
|
|
43
54
|
{children}
|
|
44
55
|
</Container>
|
|
45
56
|
);
|
|
@@ -1,9 +1,27 @@
|
|
|
1
|
-
import { ScrollView,
|
|
1
|
+
import { ScrollView, StyleSheet, useColorScheme } from 'react-native';
|
|
2
2
|
|
|
3
3
|
import { groupFieldGroupChildren } from './groupChildren';
|
|
4
4
|
import type { FieldGroupProps } from './types';
|
|
5
5
|
import { useUniversalLifecycle } from '../hooks';
|
|
6
6
|
|
|
7
|
+
const styles = StyleSheet.create({
|
|
8
|
+
container: {
|
|
9
|
+
backgroundColor: '#f2f2f7',
|
|
10
|
+
flex: 1,
|
|
11
|
+
},
|
|
12
|
+
containerDark: {
|
|
13
|
+
backgroundColor: '#000000',
|
|
14
|
+
},
|
|
15
|
+
hidden: {
|
|
16
|
+
display: 'none',
|
|
17
|
+
},
|
|
18
|
+
contentContainer: {
|
|
19
|
+
paddingHorizontal: 16,
|
|
20
|
+
paddingVertical: 16,
|
|
21
|
+
gap: 24,
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
|
|
7
25
|
/**
|
|
8
26
|
* A scrollable container for grouped settings-style rows, mirroring the look
|
|
9
27
|
* of an iOS Settings screen. Render one or more
|
|
@@ -16,7 +34,7 @@ export function FieldGroup({
|
|
|
16
34
|
style,
|
|
17
35
|
onAppear,
|
|
18
36
|
onDisappear,
|
|
19
|
-
hidden,
|
|
37
|
+
hidden = false,
|
|
20
38
|
testID,
|
|
21
39
|
}: FieldGroupProps) {
|
|
22
40
|
useUniversalLifecycle(onAppear, onDisappear);
|
|
@@ -26,36 +44,14 @@ export function FieldGroup({
|
|
|
26
44
|
return (
|
|
27
45
|
<ScrollView
|
|
28
46
|
style={[
|
|
29
|
-
|
|
30
|
-
isDarkScheme
|
|
47
|
+
styles.container,
|
|
48
|
+
isDarkScheme && styles.containerDark,
|
|
31
49
|
style,
|
|
32
|
-
hidden
|
|
50
|
+
hidden && styles.hidden,
|
|
33
51
|
]}
|
|
34
|
-
contentContainerStyle={
|
|
52
|
+
contentContainerStyle={styles.contentContainer}
|
|
35
53
|
testID={testID}>
|
|
36
54
|
{groupFieldGroupChildren(children)}
|
|
37
55
|
</ScrollView>
|
|
38
56
|
);
|
|
39
57
|
}
|
|
40
|
-
|
|
41
|
-
const containerBaseStyle: ViewStyle = {
|
|
42
|
-
flex: 1,
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
const containerLightStyle: ViewStyle = {
|
|
46
|
-
backgroundColor: '#f2f2f7',
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
const containerDarkStyle: ViewStyle = {
|
|
50
|
-
backgroundColor: '#000000',
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
const hiddenStyle: ViewStyle = {
|
|
54
|
-
display: 'none',
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
const contentContainerStyle: ViewStyle = {
|
|
58
|
-
paddingHorizontal: 16,
|
|
59
|
-
paddingVertical: 16,
|
|
60
|
-
gap: 24,
|
|
61
|
-
};
|
|
@@ -1,10 +1,62 @@
|
|
|
1
1
|
import { Fragment } from 'react';
|
|
2
|
-
import { Text, useColorScheme, View
|
|
2
|
+
import { StyleSheet, Text, useColorScheme, View } from 'react-native';
|
|
3
3
|
|
|
4
4
|
import { extractFieldSectionSlots } from './FieldSectionSlots';
|
|
5
5
|
import type { FieldSectionProps } from './types';
|
|
6
6
|
import { useUniversalLifecycle } from '../hooks';
|
|
7
7
|
|
|
8
|
+
const styles = StyleSheet.create({
|
|
9
|
+
hidden: {
|
|
10
|
+
display: 'none',
|
|
11
|
+
},
|
|
12
|
+
headerContainer: {
|
|
13
|
+
paddingHorizontal: 16,
|
|
14
|
+
paddingBottom: 8,
|
|
15
|
+
},
|
|
16
|
+
headerText: {
|
|
17
|
+
color: '#6c6c70',
|
|
18
|
+
fontSize: 14,
|
|
19
|
+
fontWeight: '500',
|
|
20
|
+
},
|
|
21
|
+
headerTextDark: {
|
|
22
|
+
color: '#98989e',
|
|
23
|
+
},
|
|
24
|
+
headerTextUppercase: {
|
|
25
|
+
textTransform: 'uppercase',
|
|
26
|
+
letterSpacing: 0.5,
|
|
27
|
+
fontSize: 13,
|
|
28
|
+
},
|
|
29
|
+
card: {
|
|
30
|
+
backgroundColor: '#ffffff',
|
|
31
|
+
borderRadius: 12,
|
|
32
|
+
overflow: 'hidden',
|
|
33
|
+
},
|
|
34
|
+
cardDark: {
|
|
35
|
+
backgroundColor: '#1c1c1e',
|
|
36
|
+
},
|
|
37
|
+
// Gives each row the same minimum height SwiftUI `Form` uses for single-line
|
|
38
|
+
// rows on iOS, so a text-only row doesn't collapse to its text intrinsic
|
|
39
|
+
// size. Taller content (e.g. a Switch) grows the row naturally. Horizontal
|
|
40
|
+
// padding matches SwiftUI `Form`'s built-in row leading/trailing inset.
|
|
41
|
+
rowWrapper: {
|
|
42
|
+
minHeight: 44,
|
|
43
|
+
justifyContent: 'center',
|
|
44
|
+
paddingHorizontal: 16,
|
|
45
|
+
},
|
|
46
|
+
divider: {
|
|
47
|
+
backgroundColor: '#e5e5ea',
|
|
48
|
+
height: 1,
|
|
49
|
+
marginLeft: 16,
|
|
50
|
+
},
|
|
51
|
+
dividerDark: {
|
|
52
|
+
backgroundColor: '#38383a',
|
|
53
|
+
},
|
|
54
|
+
footerContainer: {
|
|
55
|
+
paddingHorizontal: 16,
|
|
56
|
+
paddingTop: 8,
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
|
|
8
60
|
/**
|
|
9
61
|
* A grouped list of rows within a [`FieldGroup`](#fieldgroup). Each direct
|
|
10
62
|
* child is rendered as a single row. Use `title` for a simple caption header,
|
|
@@ -27,105 +79,35 @@ export function FieldSection({
|
|
|
27
79
|
|
|
28
80
|
const { header, footer, rows } = extractFieldSectionSlots(children);
|
|
29
81
|
|
|
30
|
-
const containerStyle: ViewStyle = {
|
|
31
|
-
...style,
|
|
32
|
-
...(hidden ? { display: 'none' } : undefined),
|
|
33
|
-
};
|
|
34
|
-
|
|
35
82
|
const headerNode =
|
|
36
83
|
header ??
|
|
37
84
|
(title ? (
|
|
38
85
|
<Text
|
|
39
86
|
style={[
|
|
40
|
-
|
|
41
|
-
isDarkScheme
|
|
42
|
-
titleUppercase
|
|
87
|
+
styles.headerText,
|
|
88
|
+
isDarkScheme && styles.headerTextDark,
|
|
89
|
+
titleUppercase && styles.headerTextUppercase,
|
|
43
90
|
]}>
|
|
44
91
|
{title}
|
|
45
92
|
</Text>
|
|
46
93
|
) : null);
|
|
47
94
|
|
|
48
95
|
return (
|
|
49
|
-
<View style={
|
|
50
|
-
{headerNode ? <View style={
|
|
96
|
+
<View style={[style, hidden && styles.hidden]} testID={testID}>
|
|
97
|
+
{headerNode ? <View style={styles.headerContainer}>{headerNode}</View> : null}
|
|
51
98
|
{rows.length > 0 ? (
|
|
52
|
-
<View style={[
|
|
99
|
+
<View style={[styles.card, isDarkScheme && styles.cardDark]}>
|
|
53
100
|
{rows.map((child, index) => (
|
|
54
101
|
<Fragment key={index}>
|
|
55
|
-
<View style={
|
|
102
|
+
<View style={styles.rowWrapper}>{child}</View>
|
|
56
103
|
{index < rows.length - 1 ? (
|
|
57
|
-
<View style={[
|
|
104
|
+
<View style={[styles.divider, isDarkScheme && styles.dividerDark]} />
|
|
58
105
|
) : null}
|
|
59
106
|
</Fragment>
|
|
60
107
|
))}
|
|
61
108
|
</View>
|
|
62
109
|
) : null}
|
|
63
|
-
{footer ? <View style={
|
|
110
|
+
{footer ? <View style={styles.footerContainer}>{footer}</View> : null}
|
|
64
111
|
</View>
|
|
65
112
|
);
|
|
66
113
|
}
|
|
67
|
-
|
|
68
|
-
const headerContainerStyle: ViewStyle = {
|
|
69
|
-
paddingHorizontal: 16,
|
|
70
|
-
paddingBottom: 8,
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
const headerTextStyle: TextStyle = {
|
|
74
|
-
fontSize: 14,
|
|
75
|
-
fontWeight: '500',
|
|
76
|
-
};
|
|
77
|
-
|
|
78
|
-
const headerTextLightStyle: TextStyle = {
|
|
79
|
-
color: '#6c6c70',
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
const headerTextDarkStyle: TextStyle = {
|
|
83
|
-
color: '#98989e',
|
|
84
|
-
};
|
|
85
|
-
|
|
86
|
-
const headerTextUppercaseStyle: TextStyle = {
|
|
87
|
-
textTransform: 'uppercase',
|
|
88
|
-
letterSpacing: 0.5,
|
|
89
|
-
fontSize: 13,
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
const cardBaseStyle: ViewStyle = {
|
|
93
|
-
borderRadius: 12,
|
|
94
|
-
overflow: 'hidden',
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
const cardLightStyle: ViewStyle = {
|
|
98
|
-
backgroundColor: '#ffffff',
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
const cardDarkStyle: ViewStyle = {
|
|
102
|
-
backgroundColor: '#1c1c1e',
|
|
103
|
-
};
|
|
104
|
-
|
|
105
|
-
// Gives each row the same minimum height SwiftUI `Form` uses for single-line
|
|
106
|
-
// rows on iOS, so a text-only row doesn't collapse to its text intrinsic
|
|
107
|
-
// size. Taller content (e.g. a Switch) grows the row naturally. Horizontal
|
|
108
|
-
// padding matches SwiftUI `Form`'s built-in row leading/trailing inset.
|
|
109
|
-
const rowWrapperStyle: ViewStyle = {
|
|
110
|
-
minHeight: 44,
|
|
111
|
-
justifyContent: 'center',
|
|
112
|
-
paddingHorizontal: 16,
|
|
113
|
-
};
|
|
114
|
-
|
|
115
|
-
const dividerStyle: ViewStyle = {
|
|
116
|
-
height: 1,
|
|
117
|
-
marginLeft: 16,
|
|
118
|
-
};
|
|
119
|
-
|
|
120
|
-
const dividerLightStyle: ViewStyle = {
|
|
121
|
-
backgroundColor: '#e5e5ea',
|
|
122
|
-
};
|
|
123
|
-
|
|
124
|
-
const dividerDarkStyle: ViewStyle = {
|
|
125
|
-
backgroundColor: '#38383a',
|
|
126
|
-
};
|
|
127
|
-
|
|
128
|
-
const footerContainerStyle: ViewStyle = {
|
|
129
|
-
paddingHorizontal: 16,
|
|
130
|
-
paddingTop: 8,
|
|
131
|
-
};
|