@fountain-ui/lab 2.0.0-beta.82 → 2.0.0-beta.84
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/build/commonjs/BottomSheet/BottomSheetNative.js +71 -17
- package/build/commonjs/BottomSheet/BottomSheetNative.js.map +1 -1
- package/build/commonjs/BottomSheet/BottomSheetProps.js.map +1 -1
- package/build/commonjs/BottomSheet/BottomSheetWeb.js +81 -12
- package/build/commonjs/BottomSheet/BottomSheetWeb.js.map +1 -1
- package/build/module/BottomSheet/BottomSheetNative.js +67 -17
- package/build/module/BottomSheet/BottomSheetNative.js.map +1 -1
- package/build/module/BottomSheet/BottomSheetProps.js.map +1 -1
- package/build/module/BottomSheet/BottomSheetWeb.js +79 -14
- package/build/module/BottomSheet/BottomSheetWeb.js.map +1 -1
- package/build/typescript/BottomSheet/BottomSheetProps.d.ts +13 -10
- package/package.json +2 -2
- package/src/BottomSheet/BottomSheetNative.tsx +82 -20
- package/src/BottomSheet/BottomSheetProps.ts +16 -12
- package/src/BottomSheet/BottomSheetWeb.tsx +95 -14
|
@@ -1,15 +1,23 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { ScrollView } from 'react-native';
|
|
3
|
-
import { Column, Modal, Paper, StyleSheet,
|
|
1
|
+
import React, { useLayoutEffect, useMemo, useState } from 'react';
|
|
2
|
+
import { LayoutChangeEvent, ScrollView, useWindowDimensions, View } from 'react-native';
|
|
3
|
+
import { Column, css, Modal, Paper, StyleSheet, useElevationStyle, useTheme } from '@fountain-ui/core';
|
|
4
4
|
import { NamedStylesStringUnion, UseStyles } from '@fountain-ui/styles';
|
|
5
5
|
import AnimatedY from '../AnimatedY';
|
|
6
6
|
import type BottomSheetProps from './BottomSheetProps';
|
|
7
7
|
import useDynamicSnapPoints from './useDynamicSnapPoints';
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
const createHeightLayoutHandler = (setHeight: React.Dispatch<React.SetStateAction<number>>) => {
|
|
10
|
+
return (event: LayoutChangeEvent) => {
|
|
11
|
+
const { height } = event.nativeEvent.layout;
|
|
12
|
+
setHeight(height);
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
type BottomSheetStyles = NamedStylesStringUnion<'root' | 'animated' | 'paper' | 'topElementLocation' | 'headerContainer' | 'headerBorder' | 'stickyBottomElement' | 'stickyBottomElementShadow'>;
|
|
10
17
|
|
|
11
18
|
const useStyles: UseStyles<BottomSheetStyles> = function (): BottomSheetStyles {
|
|
12
19
|
const theme = useTheme();
|
|
20
|
+
const stickyBottomElementShadow = useElevationStyle(8);
|
|
13
21
|
|
|
14
22
|
return {
|
|
15
23
|
root: {
|
|
@@ -34,26 +42,54 @@ const useStyles: UseStyles<BottomSheetStyles> = function (): BottomSheetStyles {
|
|
|
34
42
|
bottom: 0,
|
|
35
43
|
width: '100%',
|
|
36
44
|
},
|
|
45
|
+
headerContainer: {
|
|
46
|
+
backgroundColor: theme.palette.paper.default,
|
|
47
|
+
},
|
|
48
|
+
headerBorder: {
|
|
49
|
+
borderBottomWidth: 0.5,
|
|
50
|
+
borderBottomColor: theme.palette.divider,
|
|
51
|
+
},
|
|
52
|
+
stickyBottomElement: {
|
|
53
|
+
position: 'absolute',
|
|
54
|
+
bottom: 0,
|
|
55
|
+
left: 0,
|
|
56
|
+
right: 0,
|
|
57
|
+
backgroundColor: theme.palette.paper.default,
|
|
58
|
+
},
|
|
59
|
+
stickyBottomElementShadow,
|
|
37
60
|
};
|
|
38
61
|
};
|
|
39
62
|
|
|
40
63
|
export default function BottomSheet(props: BottomSheetProps) {
|
|
41
64
|
const {
|
|
42
65
|
backdropOpacity,
|
|
66
|
+
borderRadius,
|
|
43
67
|
children,
|
|
44
68
|
enableDynamicSizing = true,
|
|
45
69
|
header,
|
|
70
|
+
stickyBottomElement,
|
|
46
71
|
topElement,
|
|
47
72
|
index,
|
|
48
73
|
maxHeightNormalizedRatio = 0.9,
|
|
49
74
|
onChange,
|
|
50
75
|
snapPoints = [],
|
|
51
|
-
|
|
52
|
-
disableDefaultShadow = false,
|
|
76
|
+
enableScrollableHeaderBorder = false,
|
|
53
77
|
} = props;
|
|
54
78
|
|
|
55
79
|
const styles = useStyles();
|
|
56
80
|
|
|
81
|
+
const { height: windowHeight } = useWindowDimensions();
|
|
82
|
+
|
|
83
|
+
const [topElementHeight, setTopElementHeight] = useState(0);
|
|
84
|
+
const [stickyBottomElementHeight, setStickyBottomElementHeight] = useState(0);
|
|
85
|
+
const [contentHeight, setContentHeight] = useState(0);
|
|
86
|
+
const [isScrollable, setIsScrollable] = useState(false);
|
|
87
|
+
|
|
88
|
+
const maxDynamicContentSize = Math.round(windowHeight * maxHeightNormalizedRatio) - topElementHeight;
|
|
89
|
+
|
|
90
|
+
const handleTopElementLayout = createHeightLayoutHandler(setTopElementHeight);
|
|
91
|
+
const handleStickyBottomElementLayout = createHeightLayoutHandler(setStickyBottomElementHeight);
|
|
92
|
+
|
|
57
93
|
const handleClose = () => {
|
|
58
94
|
if (onChange) {
|
|
59
95
|
onChange(-1);
|
|
@@ -72,11 +108,37 @@ export default function BottomSheet(props: BottomSheetProps) {
|
|
|
72
108
|
|
|
73
109
|
const translateY = highestSnapPoint - (convertedSnapPoints[index] ?? 0);
|
|
74
110
|
|
|
75
|
-
const
|
|
111
|
+
const adjustedContentHeight = useMemo(() => {
|
|
112
|
+
const adjustedHighestSnapPoint = highestSnapPoint + stickyBottomElementHeight;
|
|
113
|
+
|
|
114
|
+
return Math.min(maxDynamicContentSize, adjustedHighestSnapPoint);
|
|
115
|
+
}, [highestSnapPoint, stickyBottomElementHeight]);
|
|
116
|
+
|
|
117
|
+
const contentStyles = [
|
|
76
118
|
styles.paper,
|
|
77
|
-
{
|
|
119
|
+
borderRadius ? { borderTopLeftRadius: borderRadius, borderTopRightRadius: borderRadius } : {},
|
|
120
|
+
{ height: adjustedContentHeight, maxHeight: maxDynamicContentSize },
|
|
121
|
+
];
|
|
122
|
+
|
|
123
|
+
const headerStyles = [
|
|
124
|
+
styles.headerContainer,
|
|
125
|
+
isScrollable && enableScrollableHeaderBorder ? styles.headerBorder : {},
|
|
126
|
+
];
|
|
127
|
+
|
|
128
|
+
const stickyBottomElementStyles = [
|
|
129
|
+
styles.stickyBottomElement,
|
|
130
|
+
isScrollable ? styles.stickyBottomElementShadow : {},
|
|
78
131
|
];
|
|
79
132
|
|
|
133
|
+
useLayoutEffect(() => {
|
|
134
|
+
if (contentHeight === 0 || highestSnapPoint === 0) {
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const adjustedHighestSnapPoint = highestSnapPoint + stickyBottomElementHeight;
|
|
139
|
+
setIsScrollable(adjustedHighestSnapPoint > maxDynamicContentSize);
|
|
140
|
+
}, [contentHeight, highestSnapPoint, stickyBottomElementHeight, maxDynamicContentSize]);
|
|
141
|
+
|
|
80
142
|
return (
|
|
81
143
|
<Modal
|
|
82
144
|
backdropOpacity={backdropOpacity}
|
|
@@ -90,25 +152,44 @@ export default function BottomSheet(props: BottomSheetProps) {
|
|
|
90
152
|
>
|
|
91
153
|
{topElement ? (
|
|
92
154
|
<Column>
|
|
93
|
-
<Column
|
|
155
|
+
<Column
|
|
156
|
+
onLayout={handleTopElementLayout}
|
|
157
|
+
style={styles.topElementLocation}
|
|
158
|
+
>
|
|
94
159
|
{topElement}
|
|
95
160
|
</Column>
|
|
96
161
|
</Column>
|
|
97
162
|
) : null}
|
|
98
163
|
|
|
99
164
|
<Paper
|
|
100
|
-
elevation={
|
|
101
|
-
style={
|
|
102
|
-
colorValue={disableDefaultBackgroundColor ? '#ffffff00' : undefined}
|
|
165
|
+
elevation={12}
|
|
166
|
+
style={contentStyles}
|
|
103
167
|
>
|
|
104
168
|
<ScrollView
|
|
105
|
-
onContentSizeChange={
|
|
169
|
+
onContentSizeChange={(contentWidth: number, contentHeight: number) => {
|
|
170
|
+
setContentHeight(contentHeight);
|
|
171
|
+
handleContentSizeChange(contentWidth, contentHeight);
|
|
172
|
+
}}
|
|
106
173
|
stickyHeaderIndices={header ? [0] : undefined}
|
|
174
|
+
style={{ paddingBottom: stickyBottomElementHeight }}
|
|
107
175
|
>
|
|
108
|
-
{header
|
|
176
|
+
{header ? (
|
|
177
|
+
<View style={headerStyles}>
|
|
178
|
+
{header}
|
|
179
|
+
</View>
|
|
180
|
+
): null}
|
|
109
181
|
|
|
110
182
|
{children}
|
|
111
183
|
</ScrollView>
|
|
184
|
+
|
|
185
|
+
{stickyBottomElement ? (
|
|
186
|
+
<Column
|
|
187
|
+
style={stickyBottomElementStyles}
|
|
188
|
+
onLayout={handleStickyBottomElementLayout}
|
|
189
|
+
>
|
|
190
|
+
{stickyBottomElement}
|
|
191
|
+
</Column>
|
|
192
|
+
): null}
|
|
112
193
|
</Paper>
|
|
113
194
|
</AnimatedY>
|
|
114
195
|
</Modal>
|