react-native-ui-lib 8.3.3 → 8.3.4-snapshot.7772
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/lib/android/build.gradle +3 -3
- package/package.json +1 -2
- package/screenFooter.d.ts +2 -0
- package/screenFooter.js +1 -0
- package/scripts/release/prReleaseNotesCommon.js +2 -1
- package/src/assets/internal/images/bottomGradient.png +0 -0
- package/src/assets/internal/images/bottomGradient@1.5x.png +0 -0
- package/src/assets/internal/images/bottomGradient@2x.png +0 -0
- package/src/assets/internal/images/bottomGradient@3x.png +0 -0
- package/src/assets/internal/images/bottomGradient@4x.png +0 -0
- package/src/assets/internal/images/index.js +3 -0
- package/src/components/screenFooter/index.d.ts +8 -0
- package/src/components/screenFooter/index.js +211 -0
- package/src/components/screenFooter/screenFooter.api.json +262 -0
- package/src/components/screenFooter/types.d.ts +100 -0
- package/src/components/screenFooter/types.js +39 -0
- package/src/components/view/index.js +9 -6
- package/src/hooks/index.d.ts +1 -0
- package/src/hooks/index.js +1 -0
- package/src/hooks/useScrollToHide/index.d.ts +24 -0
- package/src/hooks/useScrollToHide/index.js +48 -0
- package/src/incubator/expandableOverlay/index.js +7 -3
- package/src/index.d.ts +1 -0
- package/src/index.js +70 -0
package/lib/android/build.gradle
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
apply plugin: 'com.android.library'
|
|
2
2
|
|
|
3
3
|
project.ext {
|
|
4
|
-
buildToolsVersion = rootProject.ext.has("buildToolsVersion") ? rootProject.ext.buildToolsVersion : '
|
|
4
|
+
buildToolsVersion = rootProject.ext.has("buildToolsVersion") ? rootProject.ext.buildToolsVersion : '36.0.0'
|
|
5
5
|
minSdkVersion = rootProject.ext.has("minSdkVersion") ? rootProject.ext.minSdkVersion : 24
|
|
6
|
-
compileSdkVersion = rootProject.ext.has("compileSdkVersion") ? rootProject.ext.compileSdkVersion :
|
|
7
|
-
targetSdkVersion = rootProject.ext.has("targetSdkVersion") ? rootProject.ext.targetSdkVersion :
|
|
6
|
+
compileSdkVersion = rootProject.ext.has("compileSdkVersion") ? rootProject.ext.compileSdkVersion : 36
|
|
7
|
+
targetSdkVersion = rootProject.ext.has("targetSdkVersion") ? rootProject.ext.targetSdkVersion : 36
|
|
8
8
|
supportLibVersion = rootProject.ext.has("supportLibVersion") ? rootProject.ext.supportLibVersion : '28.0.0'
|
|
9
9
|
}
|
|
10
10
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-ui-lib",
|
|
3
|
-
"version": "8.3.
|
|
3
|
+
"version": "8.3.4-snapshot.7772",
|
|
4
4
|
"main": "src/index.js",
|
|
5
5
|
"types": "src/index.d.ts",
|
|
6
6
|
"author": "Ethan Sharabi <ethan.shar@gmail.com>",
|
|
@@ -112,7 +112,6 @@
|
|
|
112
112
|
"react-native": ">=0.77.3",
|
|
113
113
|
"react-native-gesture-handler": ">=2.24.0",
|
|
114
114
|
"react-native-reanimated": ">=3.17.5",
|
|
115
|
-
"react-native-safe-area-context": ">=5.6.2",
|
|
116
115
|
"uilib-native": "^5.0.1"
|
|
117
116
|
},
|
|
118
117
|
"jest": {
|
package/screenFooter.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
module.exports = require('./src/components/screenFooter').default;
|
|
@@ -9,6 +9,7 @@ const BRANCH_CATEGORIES = [
|
|
|
9
9
|
{name: 'fixes', branch: 'fix/', title: ':wrench: Fixes'},
|
|
10
10
|
{name: 'infra', branch: 'infra/', title: ':gear: Maintenance & Infra'}
|
|
11
11
|
];
|
|
12
|
+
const SILENT_PRS = ['none', 'n/a', 'na'];
|
|
12
13
|
|
|
13
14
|
function getBranchPrefixes() {
|
|
14
15
|
return BRANCH_CATEGORIES.map(category => category.branch);
|
|
@@ -95,7 +96,7 @@ function isSilent(pr) {
|
|
|
95
96
|
return true;
|
|
96
97
|
} else {
|
|
97
98
|
const changelog = pr.info.changelog.toLowerCase();
|
|
98
|
-
if (changelog
|
|
99
|
+
if (SILENT_PRS.includes(changelog)) {
|
|
99
100
|
return true;
|
|
100
101
|
}
|
|
101
102
|
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { ScreenFooterProps, ScreenFooterLayouts, ScreenFooterBackgrounds, FooterAlignment, HorizontalItemsDistribution, ItemsFit, KeyboardBehavior, ScreenFooterShadow } from './types';
|
|
3
|
+
export { ScreenFooterProps, ScreenFooterLayouts, ScreenFooterBackgrounds, FooterAlignment, HorizontalItemsDistribution, ItemsFit, KeyboardBehavior, ScreenFooterShadow };
|
|
4
|
+
declare const _default: React.ForwardRefExoticComponent<ScreenFooterProps & React.RefAttributes<any>> & {
|
|
5
|
+
(props: ScreenFooterProps): React.JSX.Element;
|
|
6
|
+
displayName: string;
|
|
7
|
+
};
|
|
8
|
+
export default _default;
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
|
2
|
+
import { StyleSheet } from 'react-native';
|
|
3
|
+
import { Image } from 'react-native-ui-lib';
|
|
4
|
+
import Animated, { useAnimatedKeyboard, useAnimatedStyle, useSharedValue, withTiming } from 'react-native-reanimated';
|
|
5
|
+
import { Keyboard } from 'uilib-native';
|
|
6
|
+
import { SafeAreaContextPackage } from "../../optionalDependencies";
|
|
7
|
+
import View from "../view";
|
|
8
|
+
import Assets from "../../assets";
|
|
9
|
+
import { Colors, Shadows, Spacings } from "../../style";
|
|
10
|
+
import { asBaseComponent, Constants } from "../../commons/new";
|
|
11
|
+
import { useKeyboardHeight } from "../../hooks";
|
|
12
|
+
import { ScreenFooterProps, ScreenFooterLayouts, ScreenFooterBackgrounds, FooterAlignment, HorizontalItemsDistribution, ItemsFit, KeyboardBehavior, ScreenFooterShadow } from "./types";
|
|
13
|
+
export { ScreenFooterProps, ScreenFooterLayouts, ScreenFooterBackgrounds, FooterAlignment, HorizontalItemsDistribution, ItemsFit, KeyboardBehavior, ScreenFooterShadow };
|
|
14
|
+
const ScreenFooter = props => {
|
|
15
|
+
const {
|
|
16
|
+
testID,
|
|
17
|
+
layout,
|
|
18
|
+
alignment,
|
|
19
|
+
horizontalAlignment,
|
|
20
|
+
backgroundType,
|
|
21
|
+
children,
|
|
22
|
+
keyboardBehavior = KeyboardBehavior.STICKY,
|
|
23
|
+
itemsFit,
|
|
24
|
+
itemWidth,
|
|
25
|
+
horizontalItemsDistribution: distribution,
|
|
26
|
+
visible = true,
|
|
27
|
+
animationDuration = 200,
|
|
28
|
+
shadow = ScreenFooterShadow.SH20,
|
|
29
|
+
hideDivider = false
|
|
30
|
+
} = props;
|
|
31
|
+
const keyboard = useAnimatedKeyboard();
|
|
32
|
+
const [height, setHeight] = useState(0);
|
|
33
|
+
const visibilityTranslateY = useSharedValue(0);
|
|
34
|
+
|
|
35
|
+
// Update visibility translation when visible or height changes
|
|
36
|
+
useEffect(() => {
|
|
37
|
+
visibilityTranslateY.value = withTiming(visible ? 0 : height, {
|
|
38
|
+
duration: animationDuration
|
|
39
|
+
});
|
|
40
|
+
}, [visible, height, animationDuration, visibilityTranslateY]);
|
|
41
|
+
|
|
42
|
+
// Animated style for STICKY behavior (counters Android system offset + visibility)
|
|
43
|
+
const stickyAnimatedStyle = useAnimatedStyle(() => {
|
|
44
|
+
const counterSystemOffset = Constants.isAndroid ? keyboard.height.value : 0;
|
|
45
|
+
return {
|
|
46
|
+
transform: [{
|
|
47
|
+
translateY: counterSystemOffset + visibilityTranslateY.value
|
|
48
|
+
}]
|
|
49
|
+
};
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
// Animated style for HOISTED behavior (visibility only, keyboard handled by KeyboardAccessoryView)
|
|
53
|
+
const hoistedAnimatedStyle = useAnimatedStyle(() => {
|
|
54
|
+
return {
|
|
55
|
+
transform: [{
|
|
56
|
+
translateY: visibilityTranslateY.value
|
|
57
|
+
}]
|
|
58
|
+
};
|
|
59
|
+
});
|
|
60
|
+
const onLayout = useCallback(event => {
|
|
61
|
+
setHeight(event.nativeEvent.layout.height);
|
|
62
|
+
}, []);
|
|
63
|
+
const isSolid = backgroundType === ScreenFooterBackgrounds.SOLID;
|
|
64
|
+
const isFading = backgroundType === ScreenFooterBackgrounds.FADING;
|
|
65
|
+
const isHorizontal = layout === ScreenFooterLayouts.HORIZONTAL;
|
|
66
|
+
const childrenCount = React.Children.count(children);
|
|
67
|
+
const justifyContent = useMemo(() => {
|
|
68
|
+
if (isHorizontal) {
|
|
69
|
+
if (distribution === HorizontalItemsDistribution.SPREAD) {
|
|
70
|
+
return childrenCount === 1 ? 'center' : 'space-between';
|
|
71
|
+
}
|
|
72
|
+
switch (horizontalAlignment) {
|
|
73
|
+
case FooterAlignment.START:
|
|
74
|
+
return 'flex-start';
|
|
75
|
+
case FooterAlignment.END:
|
|
76
|
+
return 'flex-end';
|
|
77
|
+
default:
|
|
78
|
+
return 'center';
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return 'flex-start';
|
|
82
|
+
}, [isHorizontal, distribution, horizontalAlignment, childrenCount]);
|
|
83
|
+
const alignItems = useMemo(() => {
|
|
84
|
+
if (layout === ScreenFooterLayouts.VERTICAL) {
|
|
85
|
+
if (itemsFit === ItemsFit.STRETCH) {
|
|
86
|
+
return 'stretch';
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
switch (alignment) {
|
|
90
|
+
case FooterAlignment.START:
|
|
91
|
+
return 'flex-start';
|
|
92
|
+
case FooterAlignment.END:
|
|
93
|
+
return 'flex-end';
|
|
94
|
+
default:
|
|
95
|
+
return 'center';
|
|
96
|
+
}
|
|
97
|
+
}, [layout, itemsFit, alignment]);
|
|
98
|
+
const useSafeAreaInsets = SafeAreaContextPackage?.useSafeAreaInsets ?? (() => Constants.getSafeAreaInsets());
|
|
99
|
+
const insets = useSafeAreaInsets();
|
|
100
|
+
const keyboardHeight = useKeyboardHeight();
|
|
101
|
+
const isKeyboardVisible = keyboardHeight > 0;
|
|
102
|
+
const contentContainerStyle = useMemo(() => {
|
|
103
|
+
const style = [styles.contentContainer, layout === ScreenFooterLayouts.HORIZONTAL ? styles.horizontalContainer : styles.verticalContainer, {
|
|
104
|
+
alignItems,
|
|
105
|
+
justifyContent
|
|
106
|
+
}];
|
|
107
|
+
if (!isKeyboardVisible) {
|
|
108
|
+
style.push({
|
|
109
|
+
paddingBottom: insets.bottom
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
if (isSolid) {
|
|
113
|
+
const shadowStyle = Shadows[shadow]?.top;
|
|
114
|
+
const backgroundElevation = shadowStyle?.elevation || 0;
|
|
115
|
+
// When the background has a shadow (elevation on Android), it might render on top of the content
|
|
116
|
+
style.push({
|
|
117
|
+
elevation: backgroundElevation + 1
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
return style;
|
|
121
|
+
}, [layout, alignItems, justifyContent, insets.bottom, isSolid, shadow, isKeyboardVisible]);
|
|
122
|
+
const solidBackgroundStyle = useMemo(() => {
|
|
123
|
+
if (!isSolid) {
|
|
124
|
+
return undefined;
|
|
125
|
+
}
|
|
126
|
+
const shadowStyle = Shadows[shadow]?.top;
|
|
127
|
+
const dividerStyle = hideDivider ? undefined : {
|
|
128
|
+
borderTopWidth: 1,
|
|
129
|
+
borderColor: Colors.$outlineDefault
|
|
130
|
+
};
|
|
131
|
+
return [shadowStyle, dividerStyle];
|
|
132
|
+
}, [isSolid, shadow, hideDivider]);
|
|
133
|
+
const renderBackground = useCallback(() => {
|
|
134
|
+
if (isSolid) {
|
|
135
|
+
return <View testID={testID ? `${testID}.solidBackground` : undefined} absF bg-$backgroundElevated style={solidBackgroundStyle} pointerEvents="none" />;
|
|
136
|
+
}
|
|
137
|
+
if (isFading) {
|
|
138
|
+
return <View testID={testID ? `${testID}.fadingBackground` : undefined} absF pointerEvents="none">
|
|
139
|
+
<Image source={Assets.internal.images.bottomGradient} style={styles.background} resizeMode="stretch" tintColor={Colors.$backgroundDefault} />
|
|
140
|
+
</View>;
|
|
141
|
+
}
|
|
142
|
+
return null;
|
|
143
|
+
}, [testID, isSolid, isFading, solidBackgroundStyle]);
|
|
144
|
+
const renderChild = useCallback((child, index) => {
|
|
145
|
+
if (itemsFit === ItemsFit.FIXED && itemWidth) {
|
|
146
|
+
const fixedStyle = isHorizontal ? {
|
|
147
|
+
width: itemWidth,
|
|
148
|
+
flexShrink: 1,
|
|
149
|
+
overflow: 'hidden',
|
|
150
|
+
flexDirection: 'row',
|
|
151
|
+
justifyContent: 'center'
|
|
152
|
+
} : {
|
|
153
|
+
width: itemWidth,
|
|
154
|
+
maxWidth: '100%'
|
|
155
|
+
};
|
|
156
|
+
return <View key={index} style={fixedStyle}>
|
|
157
|
+
{child}
|
|
158
|
+
</View>;
|
|
159
|
+
}
|
|
160
|
+
if (isHorizontal && React.isValidElement(child) && itemsFit === ItemsFit.STRETCH) {
|
|
161
|
+
return <View flex row centerH key={index}>
|
|
162
|
+
{child}
|
|
163
|
+
</View>;
|
|
164
|
+
}
|
|
165
|
+
return child;
|
|
166
|
+
}, [itemsFit, itemWidth, isHorizontal]);
|
|
167
|
+
const childrenArray = React.Children.toArray(children).slice(0, 3).map(renderChild);
|
|
168
|
+
const renderFooterContent = useCallback(() => {
|
|
169
|
+
return <>
|
|
170
|
+
{renderBackground()}
|
|
171
|
+
<View testID={testID ? `${testID}.content` : undefined} style={contentContainerStyle}>
|
|
172
|
+
{childrenArray}
|
|
173
|
+
</View>
|
|
174
|
+
</>;
|
|
175
|
+
}, [renderBackground, testID, contentContainerStyle, childrenArray]);
|
|
176
|
+
if (keyboardBehavior === KeyboardBehavior.HOISTED) {
|
|
177
|
+
return <Animated.View style={[styles.container, hoistedAnimatedStyle]} pointerEvents={visible ? 'box-none' : 'none'}>
|
|
178
|
+
<Keyboard.KeyboardAccessoryView renderContent={renderFooterContent} kbInputRef={undefined} scrollBehavior={Keyboard.KeyboardAccessoryView.scrollBehaviors.FIXED_OFFSET} useSafeArea={false} manageScrollView={false} revealKeyboardInteractive onHeightChanged={setHeight} />
|
|
179
|
+
</Animated.View>;
|
|
180
|
+
}
|
|
181
|
+
return <Animated.View testID={testID} onLayout={onLayout} style={[styles.container, stickyAnimatedStyle]}>
|
|
182
|
+
{renderFooterContent()}
|
|
183
|
+
</Animated.View>;
|
|
184
|
+
};
|
|
185
|
+
ScreenFooter.displayName = 'ScreenFooter';
|
|
186
|
+
const styles = StyleSheet.create({
|
|
187
|
+
container: {
|
|
188
|
+
position: 'absolute',
|
|
189
|
+
bottom: 0,
|
|
190
|
+
left: 0,
|
|
191
|
+
right: 0
|
|
192
|
+
},
|
|
193
|
+
contentContainer: {
|
|
194
|
+
paddingTop: Spacings.s4,
|
|
195
|
+
paddingHorizontal: Spacings.s5,
|
|
196
|
+
paddingBottom: Spacings.s5
|
|
197
|
+
},
|
|
198
|
+
horizontalContainer: {
|
|
199
|
+
flexDirection: 'row',
|
|
200
|
+
gap: Spacings.s5
|
|
201
|
+
},
|
|
202
|
+
verticalContainer: {
|
|
203
|
+
flexDirection: 'column',
|
|
204
|
+
gap: Spacings.s3
|
|
205
|
+
},
|
|
206
|
+
background: {
|
|
207
|
+
width: '100%',
|
|
208
|
+
height: '100%'
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
export default asBaseComponent(ScreenFooter);
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "ScreenFooter",
|
|
3
|
+
"category": "layout",
|
|
4
|
+
"description": "A flexible footer component that stays at the bottom of the screen with support for various layouts, backgrounds, and keyboard behaviors",
|
|
5
|
+
"example": "https://github.com/wix/react-native-ui-lib/blob/master/demo/src/screens/componentScreens/ScreenFooterScreen.tsx",
|
|
6
|
+
"images": [],
|
|
7
|
+
"props": [
|
|
8
|
+
{
|
|
9
|
+
"name": "backgroundType",
|
|
10
|
+
"type": "ScreenFooterBackgrounds",
|
|
11
|
+
"description": "The background style of the footer [fading, solid, transparent]",
|
|
12
|
+
"default": "'solid'"
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"name": "layout",
|
|
16
|
+
"type": "ScreenFooterLayouts",
|
|
17
|
+
"description": "The layout direction of footer items [horizontal, vertical]",
|
|
18
|
+
"default": "'vertical'"
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"name": "alignment",
|
|
22
|
+
"type": "FooterAlignment",
|
|
23
|
+
"description": "Cross-axis alignment [start, center, end]. In vertical layout: controls horizontal position. In horizontal layout: controls vertical position",
|
|
24
|
+
"default": "'center'"
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"name": "horizontalAlignment",
|
|
28
|
+
"type": "FooterAlignment",
|
|
29
|
+
"description": "Main-axis alignment for horizontal layout only when distribution is STACK [start, center, end]",
|
|
30
|
+
"default": "'center'"
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"name": "horizontalItemsDistribution",
|
|
34
|
+
"type": "HorizontalItemsDistribution",
|
|
35
|
+
"description": "Distribution of items in horizontal layout [stack, spread]",
|
|
36
|
+
"default": "'spread'"
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"name": "itemsFit",
|
|
40
|
+
"type": "ItemsFit",
|
|
41
|
+
"description": "How items should fit in vertical layout [fit, fixed, stretch]",
|
|
42
|
+
"default": "'fit'"
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
"name": "keyboardBehavior",
|
|
46
|
+
"type": "KeyboardBehavior",
|
|
47
|
+
"description": "The footer's keyboard behavior [sticky, hoisted]. Sticky: stays at bottom when keyboard opens. Hoisted: pushed up when keyboard opens",
|
|
48
|
+
"default": "'sticky'"
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"name": "itemWidth",
|
|
52
|
+
"type": "DimensionValue",
|
|
53
|
+
"description": "Fixed width for all items (used with ItemsFit.FIXED)"
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"name": "visible",
|
|
57
|
+
"type": "boolean",
|
|
58
|
+
"description": "If true, the footer is visible. If false, it slides down",
|
|
59
|
+
"default": "true"
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
"name": "animationDuration",
|
|
63
|
+
"type": "number",
|
|
64
|
+
"description": "Duration of the show/hide animation in ms",
|
|
65
|
+
"default": "200"
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"name": "useSafeArea",
|
|
69
|
+
"type": "boolean",
|
|
70
|
+
"description": "If true, the footer will respect the safe area (add bottom padding)",
|
|
71
|
+
"default": "true"
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
"name": "shadow",
|
|
75
|
+
"type": "ScreenFooterShadow",
|
|
76
|
+
"description": "Shadow preset for solid background [sh10, sh20, sh30]. Only applies when backgroundType is 'solid'",
|
|
77
|
+
"default": "'sh20'"
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
"name": "hideDivider",
|
|
81
|
+
"type": "boolean",
|
|
82
|
+
"description": "If true, hides the top divider for solid background. Only applies when backgroundType is 'solid'",
|
|
83
|
+
"default": "false"
|
|
84
|
+
}
|
|
85
|
+
],
|
|
86
|
+
"snippet": [
|
|
87
|
+
"<View flex bg-$backgroundDefault>",
|
|
88
|
+
" <ScrollView>",
|
|
89
|
+
" {/* Screen content */}",
|
|
90
|
+
" </ScrollView>",
|
|
91
|
+
" <ScreenFooter>",
|
|
92
|
+
" <Button label=\"Primary Action\" />",
|
|
93
|
+
" <Button label=\"Secondary Action\" link />",
|
|
94
|
+
" </ScreenFooter>",
|
|
95
|
+
"</View>"
|
|
96
|
+
],
|
|
97
|
+
"docs": {
|
|
98
|
+
"hero": {
|
|
99
|
+
"title": "ScreenFooter",
|
|
100
|
+
"description": "The ScreenFooter component provides a flexible footer that stays at the bottom of the screen with support for various layouts, backgrounds, and keyboard behaviors. It's ideal for forms, checkout flows, and any screen requiring persistent bottom actions.",
|
|
101
|
+
"type": "hero",
|
|
102
|
+
"layout": "horizontal",
|
|
103
|
+
"content": [
|
|
104
|
+
{
|
|
105
|
+
"value": "https://wixmp-1d257fba8470f1b562a0f5f2.wixmp.com/mads-docs-assets/assets/Components%20Docs/ScreenFooter/screenFooter_overview_preview.png"
|
|
106
|
+
}
|
|
107
|
+
]
|
|
108
|
+
},
|
|
109
|
+
"tabs": [
|
|
110
|
+
{
|
|
111
|
+
"title": "Overview",
|
|
112
|
+
"sections": [
|
|
113
|
+
{
|
|
114
|
+
"type": "section",
|
|
115
|
+
"title": "Use Examples",
|
|
116
|
+
"description": "The ScreenFooter can be used in various scenarios depending on the content and action hierarchy. Each layout type serves different use cases and provides different visual emphasis.",
|
|
117
|
+
"content": []
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
"type": "table",
|
|
121
|
+
"columns": [
|
|
122
|
+
"Layout Type",
|
|
123
|
+
"Use Case",
|
|
124
|
+
"Example"
|
|
125
|
+
],
|
|
126
|
+
"items": [
|
|
127
|
+
{
|
|
128
|
+
"title": "Horizontal - Spread",
|
|
129
|
+
"content": [
|
|
130
|
+
{
|
|
131
|
+
"value": "https://wixmp-1d257fba8470f1b562a0f5f2.wixmp.com/mads-docs-assets/assets/Components%20Docs/ScreenFooter/screenFooter_horizontal_spread.png"
|
|
132
|
+
}
|
|
133
|
+
],
|
|
134
|
+
"description": "Best for two equally important actions positioned at opposite ends. Common in navigation flows or when presenting contrasting choices."
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
"title": "Horizontal - Stacked Center",
|
|
138
|
+
"content": [
|
|
139
|
+
{
|
|
140
|
+
"value": "https://wixmp-1d257fba8470f1b562a0f5f2.wixmp.com/mads-docs-assets/assets/Components%20Docs/ScreenFooter/screenFooter_horizontal_stacked.png"
|
|
141
|
+
}
|
|
142
|
+
],
|
|
143
|
+
"description": "Ideal for primary and secondary actions of similar importance that should be grouped together in the center."
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
"title": "Horizontal - With Content",
|
|
147
|
+
"content": [
|
|
148
|
+
{
|
|
149
|
+
"value": "https://wixmp-1d257fba8470f1b562a0f5f2.wixmp.com/mads-docs-assets/assets/Components%20Docs/ScreenFooter/screenFooter_horizontal_content.png"
|
|
150
|
+
}
|
|
151
|
+
],
|
|
152
|
+
"description": "Perfect for checkout or summary screens where you need to display information alongside actions. The footer can accommodate text, prices, or other content elements."
|
|
153
|
+
}
|
|
154
|
+
],
|
|
155
|
+
"title": "Horizontal Layouts",
|
|
156
|
+
"description": "markdown: Horizontal layouts are best when screen content is abundant and vertical space is limited. They keep actions compact while maintaining good reachability. Use the `layout` prop set to `ScreenFooterLayouts.HORIZONTAL`."
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
"type": "table",
|
|
160
|
+
"columns": [
|
|
161
|
+
"Layout Type",
|
|
162
|
+
"Use Case",
|
|
163
|
+
"Example"
|
|
164
|
+
],
|
|
165
|
+
"items": [
|
|
166
|
+
{
|
|
167
|
+
"title": "Vertical - Fit",
|
|
168
|
+
"content": [
|
|
169
|
+
{
|
|
170
|
+
"value": "https://wixmp-1d257fba8470f1b562a0f5f2.wixmp.com/mads-docs-assets/assets/Components%20Docs/ScreenFooter/screenFooter_vertical_fit.png"
|
|
171
|
+
}
|
|
172
|
+
],
|
|
173
|
+
"description": "Buttons are sized based on their content. Best for clear action hierarchy with a prominent primary button and a subtle secondary link button."
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
"title": "Vertical - Stretched",
|
|
177
|
+
"content": [
|
|
178
|
+
{
|
|
179
|
+
"value": "https://wixmp-1d257fba8470f1b562a0f5f2.wixmp.com/mads-docs-assets/assets/Components%20Docs/ScreenFooter/screenFooter_vertical_stretched.png"
|
|
180
|
+
}
|
|
181
|
+
],
|
|
182
|
+
"description": "Full-width buttons provide maximum tap area and visual prominence. Recommended for forms and high-priority actions where accessibility is crucial."
|
|
183
|
+
}
|
|
184
|
+
],
|
|
185
|
+
"title": "Vertical Layouts",
|
|
186
|
+
"description": "markdown: Vertical layouts provide better action prominence and are recommended when a single primary action needs emphasis, or when content can be obscured. Use `itemsFit` prop with `ItemsFit.STRETCH` for full-width buttons or `ItemsFit.FIT` for content-sized buttons."
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
"type": "table",
|
|
190
|
+
"columns": [
|
|
191
|
+
"Background Type",
|
|
192
|
+
"Visual",
|
|
193
|
+
"When to Use"
|
|
194
|
+
],
|
|
195
|
+
"items": [
|
|
196
|
+
{
|
|
197
|
+
"title": "Solid",
|
|
198
|
+
"content": [
|
|
199
|
+
{
|
|
200
|
+
"value": "https://wixmp-1d257fba8470f1b562a0f5f2.wixmp.com/mads-docs-assets/assets/Components%20Docs/ScreenFooter/screenFooter_background_solid.png"
|
|
201
|
+
}
|
|
202
|
+
],
|
|
203
|
+
"description": "Provides clear separation with a solid background and optional shadow. Best for content-heavy screens where the footer needs to stand out."
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
"title": "Fading",
|
|
207
|
+
"content": [
|
|
208
|
+
{
|
|
209
|
+
"value": "https://wixmp-1d257fba8470f1b562a0f5f2.wixmp.com/mads-docs-assets/assets/Components%20Docs/ScreenFooter/screenFooter_background_fading.png"
|
|
210
|
+
}
|
|
211
|
+
],
|
|
212
|
+
"description": "Creates a subtle gradient overlay that doesn't obscure content completely. Ideal for minimal designs or when content should remain partially visible."
|
|
213
|
+
},
|
|
214
|
+
{
|
|
215
|
+
"title": "Transparent",
|
|
216
|
+
"content": [
|
|
217
|
+
{
|
|
218
|
+
"value": "https://wixmp-1d257fba8470f1b562a0f5f2.wixmp.com/mads-docs-assets/assets/Components%20Docs/ScreenFooter/screenFooter_background_transparent.png"
|
|
219
|
+
}
|
|
220
|
+
],
|
|
221
|
+
"description": "No background overlay. Use when the screen has minimal content or a solid background color, and separation isn't needed."
|
|
222
|
+
}
|
|
223
|
+
],
|
|
224
|
+
"title": "Background Types",
|
|
225
|
+
"description": "markdown: Choose the background type based on your content density and visual hierarchy needs. Set using the `backgroundType` prop."
|
|
226
|
+
},
|
|
227
|
+
{
|
|
228
|
+
"type": "table",
|
|
229
|
+
"columns": [
|
|
230
|
+
"Behavior",
|
|
231
|
+
"Description",
|
|
232
|
+
"Example"
|
|
233
|
+
],
|
|
234
|
+
"items": [
|
|
235
|
+
{
|
|
236
|
+
"title": "Sticky",
|
|
237
|
+
"content": [
|
|
238
|
+
{
|
|
239
|
+
"value": "https://wixmp-1d257fba8470f1b562a0f5f2.wixmp.com/mads-docs-assets/assets/Components%20Docs/ScreenFooter/screenFooter_behavior_sticky.png"
|
|
240
|
+
}
|
|
241
|
+
],
|
|
242
|
+
"description": "The footer remains at the bottom of the screen even when the keyboard is open. Best for short forms or when the footer actions don't relate to keyboard input."
|
|
243
|
+
},
|
|
244
|
+
{
|
|
245
|
+
"title": "Hoisted",
|
|
246
|
+
"content": [
|
|
247
|
+
{
|
|
248
|
+
"value": "https://wixmp-1d257fba8470f1b562a0f5f2.wixmp.com/mads-docs-assets/assets/Components%20Docs/ScreenFooter/screenFooter_behavior_hoisted.png"
|
|
249
|
+
}
|
|
250
|
+
],
|
|
251
|
+
"description": "The footer moves up with the keyboard, staying above it. Recommended for forms where users need immediate access to submit actions while typing."
|
|
252
|
+
}
|
|
253
|
+
],
|
|
254
|
+
"title": "Keyboard Behavior",
|
|
255
|
+
"description": "markdown: Control how the footer responds to the keyboard using the `keyboardBehavior` prop. Choose `KeyboardBehavior.STICKY` to keep it at the bottom, or `KeyboardBehavior.HOISTED` to move it above the keyboard."
|
|
256
|
+
}
|
|
257
|
+
]
|
|
258
|
+
}
|
|
259
|
+
]
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { PropsWithChildren } from 'react';
|
|
2
|
+
import { DimensionValue } from 'react-native';
|
|
3
|
+
export declare enum ScreenFooterLayouts {
|
|
4
|
+
HORIZONTAL = "horizontal",
|
|
5
|
+
VERTICAL = "vertical"
|
|
6
|
+
}
|
|
7
|
+
export declare enum ScreenFooterBackgrounds {
|
|
8
|
+
FADING = "fading",
|
|
9
|
+
SOLID = "solid",
|
|
10
|
+
TRANSPARENT = "transparent"
|
|
11
|
+
}
|
|
12
|
+
export declare enum FooterAlignment {
|
|
13
|
+
START = "start",
|
|
14
|
+
CENTER = "center",
|
|
15
|
+
END = "end"
|
|
16
|
+
}
|
|
17
|
+
export declare enum HorizontalItemsDistribution {
|
|
18
|
+
STACK = "stack",
|
|
19
|
+
SPREAD = "spread"
|
|
20
|
+
}
|
|
21
|
+
export declare enum ItemsFit {
|
|
22
|
+
FIT = "fit",
|
|
23
|
+
STRETCH = "stretch",
|
|
24
|
+
FIXED = "fixed"
|
|
25
|
+
}
|
|
26
|
+
export declare enum KeyboardBehavior {
|
|
27
|
+
STICKY = "sticky",
|
|
28
|
+
HOISTED = "hoisted"
|
|
29
|
+
}
|
|
30
|
+
export declare enum ScreenFooterShadow {
|
|
31
|
+
SH10 = "sh10",
|
|
32
|
+
SH20 = "sh20",
|
|
33
|
+
SH30 = "sh30"
|
|
34
|
+
}
|
|
35
|
+
export interface ScreenFooterProps extends PropsWithChildren<{}> {
|
|
36
|
+
/**
|
|
37
|
+
* Used as testing identifier
|
|
38
|
+
*/
|
|
39
|
+
testID?: string;
|
|
40
|
+
/**
|
|
41
|
+
* The background style of the footer
|
|
42
|
+
*/
|
|
43
|
+
backgroundType?: ScreenFooterBackgrounds | `${ScreenFooterBackgrounds}`;
|
|
44
|
+
/**
|
|
45
|
+
* The layout direction of footer items
|
|
46
|
+
*/
|
|
47
|
+
layout?: ScreenFooterLayouts | `${ScreenFooterLayouts}`;
|
|
48
|
+
/**
|
|
49
|
+
* Cross-axis alignment:
|
|
50
|
+
* - Vertical layout: controls horizontal position (left/center/right)
|
|
51
|
+
* - Horizontal layout: controls vertical position (top/center/bottom)
|
|
52
|
+
*/
|
|
53
|
+
alignment?: FooterAlignment | `${FooterAlignment}`;
|
|
54
|
+
/**
|
|
55
|
+
* Main-axis alignment for horizontal layout only (when distribution is STACK):
|
|
56
|
+
* Controls horizontal position (left/center/right) of the stacked items
|
|
57
|
+
*/
|
|
58
|
+
horizontalAlignment?: FooterAlignment | `${FooterAlignment}`;
|
|
59
|
+
/**
|
|
60
|
+
* Distribution of items in horizontal layout (stack/spread)
|
|
61
|
+
*/
|
|
62
|
+
horizontalItemsDistribution?: HorizontalItemsDistribution | `${HorizontalItemsDistribution}`;
|
|
63
|
+
/**
|
|
64
|
+
* How items should fit in vertical layout (fit/fixed/stretch)
|
|
65
|
+
*/
|
|
66
|
+
itemsFit?: ItemsFit | `${ItemsFit}`;
|
|
67
|
+
/**
|
|
68
|
+
* The footer's keyboard behavior.
|
|
69
|
+
* When STICKY, the footer will stay at the bottom of the screen when keyboard is opened.
|
|
70
|
+
* When HOISTED, the footer will be pushed up when keyboard is opened.
|
|
71
|
+
*/
|
|
72
|
+
keyboardBehavior?: KeyboardBehavior | `${KeyboardBehavior}`;
|
|
73
|
+
/**
|
|
74
|
+
* Fixed width for all items (used with ItemsFit.FIXED)
|
|
75
|
+
*/
|
|
76
|
+
itemWidth?: DimensionValue;
|
|
77
|
+
/**
|
|
78
|
+
* If true, the footer is visible. If false, it slides down.
|
|
79
|
+
*/
|
|
80
|
+
visible?: boolean;
|
|
81
|
+
/**
|
|
82
|
+
* Duration of the show/hide animation in ms.
|
|
83
|
+
* @default 200
|
|
84
|
+
*/
|
|
85
|
+
animationDuration?: number;
|
|
86
|
+
/**
|
|
87
|
+
* If true, the footer will respect the safe area (add bottom padding)
|
|
88
|
+
*/
|
|
89
|
+
useSafeArea?: boolean;
|
|
90
|
+
/**
|
|
91
|
+
* Shadow preset for solid background (default: SH20)
|
|
92
|
+
* Only applies when backgroundType is 'solid'
|
|
93
|
+
*/
|
|
94
|
+
shadow?: ScreenFooterShadow | `${ScreenFooterShadow}`;
|
|
95
|
+
/**
|
|
96
|
+
* If true, hides the top divider for solid background (default: false)
|
|
97
|
+
* Only applies when backgroundType is 'solid'
|
|
98
|
+
*/
|
|
99
|
+
hideDivider?: boolean;
|
|
100
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export let ScreenFooterLayouts = /*#__PURE__*/function (ScreenFooterLayouts) {
|
|
2
|
+
ScreenFooterLayouts["HORIZONTAL"] = "horizontal";
|
|
3
|
+
ScreenFooterLayouts["VERTICAL"] = "vertical";
|
|
4
|
+
return ScreenFooterLayouts;
|
|
5
|
+
}({});
|
|
6
|
+
export let ScreenFooterBackgrounds = /*#__PURE__*/function (ScreenFooterBackgrounds) {
|
|
7
|
+
ScreenFooterBackgrounds["FADING"] = "fading";
|
|
8
|
+
ScreenFooterBackgrounds["SOLID"] = "solid";
|
|
9
|
+
ScreenFooterBackgrounds["TRANSPARENT"] = "transparent";
|
|
10
|
+
return ScreenFooterBackgrounds;
|
|
11
|
+
}({});
|
|
12
|
+
export let FooterAlignment = /*#__PURE__*/function (FooterAlignment) {
|
|
13
|
+
FooterAlignment["START"] = "start";
|
|
14
|
+
FooterAlignment["CENTER"] = "center";
|
|
15
|
+
FooterAlignment["END"] = "end";
|
|
16
|
+
return FooterAlignment;
|
|
17
|
+
}({});
|
|
18
|
+
export let HorizontalItemsDistribution = /*#__PURE__*/function (HorizontalItemsDistribution) {
|
|
19
|
+
HorizontalItemsDistribution["STACK"] = "stack";
|
|
20
|
+
HorizontalItemsDistribution["SPREAD"] = "spread";
|
|
21
|
+
return HorizontalItemsDistribution;
|
|
22
|
+
}({});
|
|
23
|
+
export let ItemsFit = /*#__PURE__*/function (ItemsFit) {
|
|
24
|
+
ItemsFit["FIT"] = "fit";
|
|
25
|
+
ItemsFit["STRETCH"] = "stretch";
|
|
26
|
+
ItemsFit["FIXED"] = "fixed";
|
|
27
|
+
return ItemsFit;
|
|
28
|
+
}({});
|
|
29
|
+
export let KeyboardBehavior = /*#__PURE__*/function (KeyboardBehavior) {
|
|
30
|
+
KeyboardBehavior["STICKY"] = "sticky";
|
|
31
|
+
KeyboardBehavior["HOISTED"] = "hoisted";
|
|
32
|
+
return KeyboardBehavior;
|
|
33
|
+
}({});
|
|
34
|
+
export let ScreenFooterShadow = /*#__PURE__*/function (ScreenFooterShadow) {
|
|
35
|
+
ScreenFooterShadow["SH10"] = "sh10";
|
|
36
|
+
ScreenFooterShadow["SH20"] = "sh20";
|
|
37
|
+
ScreenFooterShadow["SH30"] = "sh30";
|
|
38
|
+
return ScreenFooterShadow;
|
|
39
|
+
}({});
|
|
@@ -2,6 +2,7 @@ import { useModifiers, useThemeProps } from "../../hooks";
|
|
|
2
2
|
import React, { useEffect, useMemo, useState } from 'react';
|
|
3
3
|
import { View as RNView, SafeAreaView, Animated } from 'react-native';
|
|
4
4
|
import { Constants } from "../../commons/new";
|
|
5
|
+
import { SafeAreaContextPackage } from "../../optionalDependencies";
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Extra props when using reanimated (only non experimental props)
|
|
@@ -65,7 +66,12 @@ function View(props, ref) {
|
|
|
65
66
|
}
|
|
66
67
|
}, []);
|
|
67
68
|
const ViewContainer = useMemo(() => {
|
|
68
|
-
|
|
69
|
+
let container = RNView;
|
|
70
|
+
if (useSafeArea && SafeAreaContextPackage?.SafeAreaView) {
|
|
71
|
+
container = SafeAreaContextPackage.SafeAreaView;
|
|
72
|
+
} else if (useSafeArea && Constants.isIOS) {
|
|
73
|
+
container = SafeAreaView;
|
|
74
|
+
}
|
|
69
75
|
if (reanimated) {
|
|
70
76
|
const {
|
|
71
77
|
default: Reanimated
|
|
@@ -89,11 +95,8 @@ function View(props, ref) {
|
|
|
89
95
|
if (!ready) {
|
|
90
96
|
return null;
|
|
91
97
|
}
|
|
92
|
-
return
|
|
93
|
-
//@ts-expect-error
|
|
94
|
-
<ViewContainer accessibilityElementsHidden={inaccessible} importantForAccessibility={inaccessible ? 'no-hide-descendants' : undefined} fsTagName={recorderTag} {...others} style={_style} ref={ref}>
|
|
98
|
+
return <ViewContainer accessibilityElementsHidden={inaccessible} importantForAccessibility={inaccessible ? 'no-hide-descendants' : undefined} fsTagName={recorderTag} {...others} style={_style} ref={ref}>
|
|
95
99
|
{children}
|
|
96
|
-
</ViewContainer
|
|
97
|
-
);
|
|
100
|
+
</ViewContainer>;
|
|
98
101
|
}
|
|
99
102
|
export default React.forwardRef(View);
|
package/src/hooks/index.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ export { default as useModifiers } from './useModifiers';
|
|
|
6
6
|
export { default as useOrientation } from './useOrientation';
|
|
7
7
|
export { default as useScrollEnabler } from './useScrollEnabler';
|
|
8
8
|
export { default as useScrollReached } from './useScrollReached';
|
|
9
|
+
export { default as useScrollToHide } from './useScrollToHide';
|
|
9
10
|
export { default as useScrollToItem } from './useScrollToItem';
|
|
10
11
|
export { default as useScrollTo } from './useScrollTo';
|
|
11
12
|
export { default as useThemeProps } from './useThemeProps';
|
package/src/hooks/index.js
CHANGED
|
@@ -6,6 +6,7 @@ export { default as useModifiers } from "./useModifiers";
|
|
|
6
6
|
export { default as useOrientation } from "./useOrientation";
|
|
7
7
|
export { default as useScrollEnabler } from "./useScrollEnabler";
|
|
8
8
|
export { default as useScrollReached } from "./useScrollReached";
|
|
9
|
+
export { default as useScrollToHide } from "./useScrollToHide";
|
|
9
10
|
export { default as useScrollToItem } from "./useScrollToItem";
|
|
10
11
|
export { default as useScrollTo } from "./useScrollTo";
|
|
11
12
|
export { default as useThemeProps } from "./useThemeProps";
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { NativeSyntheticEvent, NativeScrollEvent } from 'react-native';
|
|
2
|
+
export type ScrollToHideProps = {
|
|
3
|
+
/**
|
|
4
|
+
* The threshold (in pixels) to ignore small scroll movements before updating visibility.
|
|
5
|
+
* Defaults to 0 (immediate reaction).
|
|
6
|
+
*/
|
|
7
|
+
scrollingThreshold?: number;
|
|
8
|
+
};
|
|
9
|
+
export type ScrollToHideResult = {
|
|
10
|
+
/**
|
|
11
|
+
* onScroll callback (should be passed to your ScrollView/FlatList onScroll prop).
|
|
12
|
+
*/
|
|
13
|
+
onScroll: (event: NativeSyntheticEvent<NativeScrollEvent>) => void;
|
|
14
|
+
/**
|
|
15
|
+
* Whether the footer should be visible based on scroll direction.
|
|
16
|
+
*/
|
|
17
|
+
visible: boolean;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* @description: A hook that tracks scroll direction to toggle visibility (e.g., for hiding a footer on scroll).
|
|
21
|
+
* @example: const {onScroll, visible} = useScrollToHide();
|
|
22
|
+
*/
|
|
23
|
+
declare const useScrollToHide: (props?: ScrollToHideProps) => ScrollToHideResult;
|
|
24
|
+
export default useScrollToHide;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { useState, useCallback, useRef } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* @description: A hook that tracks scroll direction to toggle visibility (e.g., for hiding a footer on scroll).
|
|
4
|
+
* @example: const {onScroll, visible} = useScrollToHide();
|
|
5
|
+
*/
|
|
6
|
+
const useScrollToHide = (props = {}) => {
|
|
7
|
+
const {
|
|
8
|
+
scrollingThreshold = 0
|
|
9
|
+
} = props;
|
|
10
|
+
const [visible, setVisible] = useState(true);
|
|
11
|
+
const prevContentOffset = useRef(0);
|
|
12
|
+
const onScroll = useCallback(event => {
|
|
13
|
+
const {
|
|
14
|
+
nativeEvent: {
|
|
15
|
+
contentOffset: {
|
|
16
|
+
y: currentOffset
|
|
17
|
+
},
|
|
18
|
+
contentSize: {
|
|
19
|
+
height: contentHeight
|
|
20
|
+
},
|
|
21
|
+
layoutMeasurement: {
|
|
22
|
+
height: layoutHeight
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
} = event;
|
|
26
|
+
|
|
27
|
+
// Ignore bounces (iOS)
|
|
28
|
+
if (currentOffset < 0 || currentOffset > contentHeight - layoutHeight) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
const diff = currentOffset - prevContentOffset.current;
|
|
32
|
+
if (Math.abs(diff) > scrollingThreshold) {
|
|
33
|
+
if (diff > 0 && visible) {
|
|
34
|
+
// Scrolling Down -> Hide
|
|
35
|
+
setVisible(false);
|
|
36
|
+
} else if (diff < 0 && !visible) {
|
|
37
|
+
// Scrolling Up -> Show
|
|
38
|
+
setVisible(true);
|
|
39
|
+
}
|
|
40
|
+
prevContentOffset.current = currentOffset;
|
|
41
|
+
}
|
|
42
|
+
}, [visible, scrollingThreshold]);
|
|
43
|
+
return {
|
|
44
|
+
onScroll,
|
|
45
|
+
visible
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
export default useScrollToHide;
|
|
@@ -33,11 +33,15 @@ const ExpandableOverlay = (props, ref) => {
|
|
|
33
33
|
setExpandableVisible(true);
|
|
34
34
|
onPress?.(props);
|
|
35
35
|
}, [onPress, customValue]);
|
|
36
|
-
const
|
|
36
|
+
const dismissOverlay = useCallback(() => {
|
|
37
37
|
setExpandableVisible(false);
|
|
38
38
|
focusAccessibility();
|
|
39
|
+
}, [focusAccessibility]);
|
|
40
|
+
const closeExpandable = useCallback(() => {
|
|
41
|
+
dismissOverlay();
|
|
39
42
|
useDialog ? dialogProps?.onDismiss?.() : modalProps?.onDismiss?.();
|
|
40
|
-
|
|
43
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
44
|
+
}, [dismissOverlay, dialogProps?.onDismiss, modalProps?.onDismiss]);
|
|
41
45
|
const toggleExpandable = useCallback(() => visible ? closeExpandable() : openExpandable(), [visible, openExpandable, closeExpandable]);
|
|
42
46
|
useImperativeHandle(ref, () => ({
|
|
43
47
|
openExpandable,
|
|
@@ -45,7 +49,7 @@ const ExpandableOverlay = (props, ref) => {
|
|
|
45
49
|
toggleExpandable
|
|
46
50
|
}));
|
|
47
51
|
const renderModal = () => {
|
|
48
|
-
return <Modal testID={`${testID}.overlay`} overlayBackgroundColor={Colors.$backgroundDefault} {...modalProps} visible={visible} onDismiss={
|
|
52
|
+
return <Modal testID={`${testID}.overlay`} overlayBackgroundColor={Colors.$backgroundDefault} {...modalProps} visible={visible} onDismiss={dismissOverlay} onRequestClose={closeExpandable} onBackgroundPress={closeExpandable}>
|
|
49
53
|
{showTopBar && <Modal.TopBar onDone={closeExpandable} {...topBarProps} />}
|
|
50
54
|
{expandableContent}
|
|
51
55
|
</Modal>;
|
package/src/index.d.ts
CHANGED
|
@@ -38,6 +38,7 @@ export { default as ExpandableSection, ExpandableSectionProps } from './componen
|
|
|
38
38
|
export { default as Fader, FaderProps, FaderPosition } from './components/fader';
|
|
39
39
|
export { default as FeatureHighlight, FeatureHighlightProps } from './components/featureHighlight';
|
|
40
40
|
export { default as FloatingButton, FloatingButtonProps, FloatingButtonLayouts } from './components/floatingButton';
|
|
41
|
+
export { default as ScreenFooter, ScreenFooterProps, ScreenFooterLayouts, ScreenFooterBackgrounds, FooterAlignment, HorizontalItemsDistribution, ItemsFit, KeyboardBehavior, ScreenFooterShadow } from './components/screenFooter';
|
|
41
42
|
export { default as Gradient, GradientProps, GradientTypes } from './components/gradient';
|
|
42
43
|
export { default as Slider } from './components/slider';
|
|
43
44
|
export { default as GradientSlider } from './components/slider/GradientSlider';
|
package/src/index.js
CHANGED
|
@@ -99,6 +99,15 @@ var _exportNames = {
|
|
|
99
99
|
FloatingButton: true,
|
|
100
100
|
FloatingButtonProps: true,
|
|
101
101
|
FloatingButtonLayouts: true,
|
|
102
|
+
ScreenFooter: true,
|
|
103
|
+
ScreenFooterProps: true,
|
|
104
|
+
ScreenFooterLayouts: true,
|
|
105
|
+
ScreenFooterBackgrounds: true,
|
|
106
|
+
FooterAlignment: true,
|
|
107
|
+
HorizontalItemsDistribution: true,
|
|
108
|
+
ItemsFit: true,
|
|
109
|
+
KeyboardBehavior: true,
|
|
110
|
+
ScreenFooterShadow: true,
|
|
102
111
|
Gradient: true,
|
|
103
112
|
GradientProps: true,
|
|
104
113
|
GradientTypes: true,
|
|
@@ -699,6 +708,12 @@ Object.defineProperty(exports, "FloatingButtonProps", {
|
|
|
699
708
|
return _floatingButton().FloatingButtonProps;
|
|
700
709
|
}
|
|
701
710
|
});
|
|
711
|
+
Object.defineProperty(exports, "FooterAlignment", {
|
|
712
|
+
enumerable: true,
|
|
713
|
+
get: function () {
|
|
714
|
+
return _screenFooter().FooterAlignment;
|
|
715
|
+
}
|
|
716
|
+
});
|
|
702
717
|
Object.defineProperty(exports, "ForwardRefInjectedProps", {
|
|
703
718
|
enumerable: true,
|
|
704
719
|
get: function () {
|
|
@@ -790,6 +805,12 @@ Object.defineProperty(exports, "HintProps", {
|
|
|
790
805
|
}
|
|
791
806
|
});
|
|
792
807
|
exports.Hooks = void 0;
|
|
808
|
+
Object.defineProperty(exports, "HorizontalItemsDistribution", {
|
|
809
|
+
enumerable: true,
|
|
810
|
+
get: function () {
|
|
811
|
+
return _screenFooter().HorizontalItemsDistribution;
|
|
812
|
+
}
|
|
813
|
+
});
|
|
793
814
|
Object.defineProperty(exports, "Icon", {
|
|
794
815
|
enumerable: true,
|
|
795
816
|
get: function () {
|
|
@@ -815,6 +836,12 @@ Object.defineProperty(exports, "ImageProps", {
|
|
|
815
836
|
}
|
|
816
837
|
});
|
|
817
838
|
exports.Incubator = void 0;
|
|
839
|
+
Object.defineProperty(exports, "ItemsFit", {
|
|
840
|
+
enumerable: true,
|
|
841
|
+
get: function () {
|
|
842
|
+
return _screenFooter().ItemsFit;
|
|
843
|
+
}
|
|
844
|
+
});
|
|
818
845
|
Object.defineProperty(exports, "KeyboardAwareFlatList", {
|
|
819
846
|
enumerable: true,
|
|
820
847
|
get: function () {
|
|
@@ -827,6 +854,12 @@ Object.defineProperty(exports, "KeyboardAwareScrollView", {
|
|
|
827
854
|
return _KeyboardAwareScrollView().default;
|
|
828
855
|
}
|
|
829
856
|
});
|
|
857
|
+
Object.defineProperty(exports, "KeyboardBehavior", {
|
|
858
|
+
enumerable: true,
|
|
859
|
+
get: function () {
|
|
860
|
+
return _screenFooter().KeyboardBehavior;
|
|
861
|
+
}
|
|
862
|
+
});
|
|
830
863
|
Object.defineProperty(exports, "ListItem", {
|
|
831
864
|
enumerable: true,
|
|
832
865
|
get: function () {
|
|
@@ -1146,6 +1179,36 @@ Object.defineProperty(exports, "RenderCustomModalProps", {
|
|
|
1146
1179
|
return _picker().RenderCustomModalProps;
|
|
1147
1180
|
}
|
|
1148
1181
|
});
|
|
1182
|
+
Object.defineProperty(exports, "ScreenFooter", {
|
|
1183
|
+
enumerable: true,
|
|
1184
|
+
get: function () {
|
|
1185
|
+
return _screenFooter().default;
|
|
1186
|
+
}
|
|
1187
|
+
});
|
|
1188
|
+
Object.defineProperty(exports, "ScreenFooterBackgrounds", {
|
|
1189
|
+
enumerable: true,
|
|
1190
|
+
get: function () {
|
|
1191
|
+
return _screenFooter().ScreenFooterBackgrounds;
|
|
1192
|
+
}
|
|
1193
|
+
});
|
|
1194
|
+
Object.defineProperty(exports, "ScreenFooterLayouts", {
|
|
1195
|
+
enumerable: true,
|
|
1196
|
+
get: function () {
|
|
1197
|
+
return _screenFooter().ScreenFooterLayouts;
|
|
1198
|
+
}
|
|
1199
|
+
});
|
|
1200
|
+
Object.defineProperty(exports, "ScreenFooterProps", {
|
|
1201
|
+
enumerable: true,
|
|
1202
|
+
get: function () {
|
|
1203
|
+
return _screenFooter().ScreenFooterProps;
|
|
1204
|
+
}
|
|
1205
|
+
});
|
|
1206
|
+
Object.defineProperty(exports, "ScreenFooterShadow", {
|
|
1207
|
+
enumerable: true,
|
|
1208
|
+
get: function () {
|
|
1209
|
+
return _screenFooter().ScreenFooterShadow;
|
|
1210
|
+
}
|
|
1211
|
+
});
|
|
1149
1212
|
Object.defineProperty(exports, "ScrollBar", {
|
|
1150
1213
|
enumerable: true,
|
|
1151
1214
|
get: function () {
|
|
@@ -1906,6 +1969,13 @@ function _floatingButton() {
|
|
|
1906
1969
|
};
|
|
1907
1970
|
return data;
|
|
1908
1971
|
}
|
|
1972
|
+
function _screenFooter() {
|
|
1973
|
+
const data = _interopRequireWildcard(require("./components/screenFooter"));
|
|
1974
|
+
_screenFooter = function () {
|
|
1975
|
+
return data;
|
|
1976
|
+
};
|
|
1977
|
+
return data;
|
|
1978
|
+
}
|
|
1909
1979
|
function _gradient() {
|
|
1910
1980
|
const data = _interopRequireWildcard(require("./components/gradient"));
|
|
1911
1981
|
_gradient = function () {
|