@utilitywarehouse/hearth-react-native 0.29.0 → 0.29.2
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/.turbo/turbo-build.log +1 -1
- package/.turbo/turbo-lint.log +13 -13
- package/CHANGELOG.md +42 -0
- package/build/components/BottomSheet/BottomSheet.context.d.ts +1 -0
- package/build/components/BottomSheet/BottomSheet.context.js +3 -1
- package/build/components/BottomSheet/BottomSheet.js +5 -1
- package/build/components/BottomSheet/BottomSheetFlatList.js +16 -2
- package/build/components/BottomSheet/BottomSheetModal.js +5 -1
- package/build/components/BottomSheet/BottomSheetModalProvider.d.ts +9 -0
- package/build/components/BottomSheet/BottomSheetModalProvider.js +14 -0
- package/build/components/BottomSheet/BottomSheetScrollView.js +16 -2
- package/build/components/BottomSheet/BottomSheetView.js +16 -2
- package/build/components/BottomSheet/index.d.ts +3 -1
- package/build/components/BottomSheet/index.js +2 -1
- package/build/components/Combobox/Combobox.js +3 -1
- package/build/components/Modal/Modal.js +54 -8
- package/build/components/NavModal/NavModal.js +3 -3
- package/build/components/Select/Select.js +3 -1
- package/package.json +1 -1
- package/src/components/BottomSheet/BottomSheet.context.ts +4 -1
- package/src/components/BottomSheet/BottomSheet.docs.mdx +20 -0
- package/src/components/BottomSheet/BottomSheet.tsx +8 -1
- package/src/components/BottomSheet/BottomSheetFlatList.tsx +16 -2
- package/src/components/BottomSheet/BottomSheetModal.tsx +8 -1
- package/src/components/BottomSheet/BottomSheetModalProvider.tsx +33 -0
- package/src/components/BottomSheet/BottomSheetScrollView.tsx +16 -2
- package/src/components/BottomSheet/BottomSheetView.tsx +17 -2
- package/src/components/BottomSheet/index.ts +2 -1
- package/src/components/Combobox/Combobox.tsx +3 -1
- package/src/components/Modal/Modal.docs.mdx +14 -0
- package/src/components/Modal/Modal.tsx +54 -8
- package/src/components/NavModal/NavModal.tsx +3 -3
- package/src/components/Select/Select.tsx +3 -1
package/.turbo/turbo-build.log
CHANGED
package/.turbo/turbo-lint.log
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
> @utilitywarehouse/hearth-react-native@0.29.
|
|
2
|
+
> @utilitywarehouse/hearth-react-native@0.29.2 lint /home/runner/work/hearth/hearth/packages/react-native
|
|
3
3
|
> TIMING=1 eslint .
|
|
4
4
|
|
|
5
5
|
|
|
@@ -51,15 +51,15 @@
|
|
|
51
51
|
|
|
52
52
|
✖ 22 problems (0 errors, 22 warnings)
|
|
53
53
|
|
|
54
|
-
Rule
|
|
55
|
-
|
|
56
|
-
@typescript-eslint/no-unused-vars
|
|
57
|
-
react-hooks/exhaustive-deps
|
|
58
|
-
no-global-assign
|
|
59
|
-
react-hooks/rules-of-hooks
|
|
60
|
-
no-
|
|
61
|
-
|
|
62
|
-
no-
|
|
63
|
-
no-
|
|
64
|
-
|
|
65
|
-
@typescript-eslint/
|
|
54
|
+
Rule | Time (ms) | Relative
|
|
55
|
+
:----------------------------------------|----------:|--------:
|
|
56
|
+
@typescript-eslint/no-unused-vars | 1520.806 | 60.5%
|
|
57
|
+
react-hooks/exhaustive-deps | 119.554 | 4.8%
|
|
58
|
+
no-global-assign | 82.827 | 3.3%
|
|
59
|
+
react-hooks/rules-of-hooks | 73.620 | 2.9%
|
|
60
|
+
no-loss-of-precision | 46.636 | 1.9%
|
|
61
|
+
no-unexpected-multiline | 38.241 | 1.5%
|
|
62
|
+
no-misleading-character-class | 37.413 | 1.5%
|
|
63
|
+
@typescript-eslint/no-unused-expressions | 31.682 | 1.3%
|
|
64
|
+
no-useless-escape | 28.666 | 1.1%
|
|
65
|
+
@typescript-eslint/ban-ts-comment | 27.948 | 1.1%
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,47 @@
|
|
|
1
1
|
# @utilitywarehouse/hearth-react-native
|
|
2
2
|
|
|
3
|
+
## 0.29.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#1067](https://github.com/utilitywarehouse/hearth/pull/1067) [`893cbfd`](https://github.com/utilitywarehouse/hearth/commit/893cbfd1bf090b8b75df6f58f2babaf8ba1e0033) Thanks [@jordmccord](https://github.com/jordmccord)! - 🌟 [FEATURE]: Add a `useSafeAreaInsets` prop to `BottomSheetModalProvider` to control Hearth's bottom-sheet safe-area spacing.
|
|
8
|
+
|
|
9
|
+
Bottom-sheet wrappers such as `BottomSheetView`, `BottomSheetScrollView`, `BottomSheetFlatList`, and components that render `SafeAreaView` inside a bottom sheet now respect `BottomSheetModalProvider` configuration.
|
|
10
|
+
|
|
11
|
+
**Components affected**:
|
|
12
|
+
- `BottomSheetModalProvider`
|
|
13
|
+
- `BottomSheetView`
|
|
14
|
+
- `BottomSheetScrollView`
|
|
15
|
+
- `BottomSheetFlatList`
|
|
16
|
+
- `Modal`
|
|
17
|
+
- `Select`
|
|
18
|
+
- `Combobox`
|
|
19
|
+
|
|
20
|
+
**Developer changes**:
|
|
21
|
+
|
|
22
|
+
No changes are required if you want the current behaviour. If your app already applies its own safe-area padding around bottom-sheet content, opt out like this:
|
|
23
|
+
|
|
24
|
+
```tsx
|
|
25
|
+
<BottomSheetModalProvider useSafeAreaInsets={false}>
|
|
26
|
+
{/* Your app content */}
|
|
27
|
+
</BottomSheetModalProvider>
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## 0.29.1
|
|
31
|
+
|
|
32
|
+
### Patch Changes
|
|
33
|
+
|
|
34
|
+
- [#1062](https://github.com/utilitywarehouse/hearth/pull/1062) [`0da3ffe`](https://github.com/utilitywarehouse/hearth/commit/0da3ffe12691a4287694ae9fcb2290d459e3c041) Thanks [@jordmccord](https://github.com/jordmccord)! - 🐛 [FIX]: Respect the selected `NavModal` background style
|
|
35
|
+
|
|
36
|
+
Fixed an issue where `NavModal` always rendered its inner content with the default surface background, which prevented the `background="brand"` treatment from being applied correctly.
|
|
37
|
+
|
|
38
|
+
**Components affected**:
|
|
39
|
+
- `NavModal`
|
|
40
|
+
|
|
41
|
+
**Developer changes**:
|
|
42
|
+
|
|
43
|
+
No changes are required.
|
|
44
|
+
|
|
3
45
|
## 0.29.0
|
|
4
46
|
|
|
5
47
|
### Minor Changes
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { createContext, useContext } from 'react';
|
|
2
|
-
export const BottomSheetContext = createContext({
|
|
2
|
+
export const BottomSheetContext = createContext({
|
|
3
|
+
useSafeAreaInsets: true,
|
|
4
|
+
});
|
|
3
5
|
export const useBottomSheetContext = () => {
|
|
4
6
|
const context = useContext(BottomSheetContext);
|
|
5
7
|
return context;
|
|
@@ -7,6 +7,7 @@ import useBottomSheetLogic from './useBottomSheetLogic';
|
|
|
7
7
|
const StyledBottomSheetCore = withUnistyles(BottomSheetCore);
|
|
8
8
|
const BottomSheet = ({ children, containerStyle, handleStyle, backdrop = true, showHandle = true, ref, ...rest }) => {
|
|
9
9
|
const bottomSheetRef = React.useRef(null);
|
|
10
|
+
const parentContext = React.useContext(BottomSheetContext);
|
|
10
11
|
const { renderBackdrop, renderHandle } = useBottomSheetLogic({
|
|
11
12
|
ref,
|
|
12
13
|
bottomSheetRef,
|
|
@@ -14,7 +15,10 @@ const BottomSheet = ({ children, containerStyle, handleStyle, backdrop = true, s
|
|
|
14
15
|
showHandle,
|
|
15
16
|
handleStyle,
|
|
16
17
|
});
|
|
17
|
-
const value = useMemo(() => ({
|
|
18
|
+
const value = useMemo(() => ({
|
|
19
|
+
...parentContext,
|
|
20
|
+
handle: showHandle,
|
|
21
|
+
}), [parentContext, showHandle]);
|
|
18
22
|
return (_jsx(StyledBottomSheetCore, { ref: bottomSheetRef, index: -1, backdropComponent: renderBackdrop, handleComponent: renderHandle, style: [styles.container, containerStyle], backgroundStyle: styles.background, ...rest, children: _jsx(BottomSheetContext.Provider, { value: value, children: children }) }));
|
|
19
23
|
};
|
|
20
24
|
const styles = StyleSheet.create(theme => ({
|
|
@@ -4,10 +4,11 @@ import { StyleSheet, withUnistyles } from 'react-native-unistyles';
|
|
|
4
4
|
import { useBottomSheetContext } from './BottomSheet.context';
|
|
5
5
|
const StyledBottomSheetFlatList = withUnistyles(FlatList);
|
|
6
6
|
const BottomSheetFlatList = ({ style, contentContainerStyle, isModal = true, ...props }) => {
|
|
7
|
-
const { handle } = useBottomSheetContext();
|
|
7
|
+
const { handle, useSafeAreaInsets } = useBottomSheetContext();
|
|
8
8
|
styles.useVariants({
|
|
9
9
|
isModal,
|
|
10
10
|
handle,
|
|
11
|
+
useSafeAreaInsets,
|
|
11
12
|
});
|
|
12
13
|
return (_jsx(StyledBottomSheetFlatList, { style: [styles.container, style], contentContainerStyle: [styles.contentContainer, contentContainerStyle], ...props }));
|
|
13
14
|
};
|
|
@@ -19,7 +20,7 @@ const styles = StyleSheet.create((theme, rt) => ({
|
|
|
19
20
|
variants: {
|
|
20
21
|
isModal: {
|
|
21
22
|
true: {
|
|
22
|
-
paddingBottom: theme.components.bottomSheet.padding
|
|
23
|
+
paddingBottom: theme.components.bottomSheet.padding,
|
|
23
24
|
},
|
|
24
25
|
},
|
|
25
26
|
handle: {
|
|
@@ -27,7 +28,20 @@ const styles = StyleSheet.create((theme, rt) => ({
|
|
|
27
28
|
paddingTop: theme.components.bottomSheet.padding,
|
|
28
29
|
},
|
|
29
30
|
},
|
|
31
|
+
useSafeAreaInsets: {
|
|
32
|
+
true: {},
|
|
33
|
+
false: {},
|
|
34
|
+
},
|
|
30
35
|
},
|
|
36
|
+
compoundVariants: [
|
|
37
|
+
{
|
|
38
|
+
isModal: true,
|
|
39
|
+
useSafeAreaInsets: true,
|
|
40
|
+
styles: {
|
|
41
|
+
paddingBottom: theme.components.bottomSheet.padding + rt.insets.bottom,
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
],
|
|
31
45
|
},
|
|
32
46
|
}));
|
|
33
47
|
BottomSheetFlatList.displayName = 'BottomSheetFlatList';
|
|
@@ -7,6 +7,7 @@ import useBottomSheetLogic from './useBottomSheetLogic';
|
|
|
7
7
|
const StyledBottomSheetModalCore = withUnistyles(BottomSheetModalCore);
|
|
8
8
|
const BottomSheetModal = ({ children, containerStyle, handleStyle, backdrop = true, showHandle = true, ref, ...rest }) => {
|
|
9
9
|
const bottomSheetRef = React.useRef(null);
|
|
10
|
+
const parentContext = React.useContext(BottomSheetContext);
|
|
10
11
|
const { renderBackdrop, renderHandle } = useBottomSheetLogic({
|
|
11
12
|
// @ts-expect-error - ref
|
|
12
13
|
ref,
|
|
@@ -15,7 +16,10 @@ const BottomSheetModal = ({ children, containerStyle, handleStyle, backdrop = tr
|
|
|
15
16
|
showHandle,
|
|
16
17
|
handleStyle,
|
|
17
18
|
});
|
|
18
|
-
const value = useMemo(() => ({
|
|
19
|
+
const value = useMemo(() => ({
|
|
20
|
+
...parentContext,
|
|
21
|
+
handle: showHandle,
|
|
22
|
+
}), [parentContext, showHandle]);
|
|
19
23
|
return (_jsx(StyledBottomSheetModalCore, { ref: bottomSheetRef, backdropComponent: renderBackdrop, handleComponent: renderHandle, style: [styles.container, containerStyle], backgroundStyle: styles.background, ...rest, children: _jsx(BottomSheetContext.Provider, { value: value, children: children }) }));
|
|
20
24
|
};
|
|
21
25
|
const styles = StyleSheet.create(theme => ({
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { BottomSheetModalProviderProps as GorhomBottomSheetModalProviderProps } from '@gorhom/bottom-sheet/lib/typescript/components/bottomSheetModalProvider/types';
|
|
2
|
+
export interface BottomSheetModalProviderProps extends GorhomBottomSheetModalProviderProps {
|
|
3
|
+
useSafeAreaInsets?: boolean;
|
|
4
|
+
}
|
|
5
|
+
declare const BottomSheetModalProvider: {
|
|
6
|
+
({ children, useSafeAreaInsets, ...props }: BottomSheetModalProviderProps): import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
displayName: string;
|
|
8
|
+
};
|
|
9
|
+
export default BottomSheetModalProvider;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { BottomSheetModalProvider as GorhomBottomSheetModalProvider } from '@gorhom/bottom-sheet';
|
|
3
|
+
import { useMemo } from 'react';
|
|
4
|
+
import { BottomSheetContext, useBottomSheetContext } from './BottomSheet.context';
|
|
5
|
+
const BottomSheetModalProvider = ({ children, useSafeAreaInsets = true, ...props }) => {
|
|
6
|
+
const parentContext = useBottomSheetContext();
|
|
7
|
+
const value = useMemo(() => ({
|
|
8
|
+
...parentContext,
|
|
9
|
+
useSafeAreaInsets,
|
|
10
|
+
}), [parentContext, useSafeAreaInsets]);
|
|
11
|
+
return (_jsx(GorhomBottomSheetModalProvider, { ...props, children: _jsx(BottomSheetContext.Provider, { value: value, children: children }) }));
|
|
12
|
+
};
|
|
13
|
+
BottomSheetModalProvider.displayName = 'BottomSheetModalProvider';
|
|
14
|
+
export default BottomSheetModalProvider;
|
|
@@ -4,10 +4,11 @@ import { StyleSheet, withUnistyles } from 'react-native-unistyles';
|
|
|
4
4
|
import { useBottomSheetContext } from './BottomSheet.context';
|
|
5
5
|
const StyledBottomSheetScrollView = withUnistyles(ScrollView);
|
|
6
6
|
const BottomSheetScrollView = ({ children, style, contentContainerStyle, isModal = true, ...props }) => {
|
|
7
|
-
const { handle } = useBottomSheetContext();
|
|
7
|
+
const { handle, useSafeAreaInsets } = useBottomSheetContext();
|
|
8
8
|
styles.useVariants({
|
|
9
9
|
isModal,
|
|
10
10
|
handle,
|
|
11
|
+
useSafeAreaInsets,
|
|
11
12
|
});
|
|
12
13
|
return (_jsx(StyledBottomSheetScrollView, { style: [styles.container, style], contentContainerStyle: [styles.contentContainer, contentContainerStyle], ...props, children: children }));
|
|
13
14
|
};
|
|
@@ -23,7 +24,7 @@ const styles = StyleSheet.create((theme, rt) => ({
|
|
|
23
24
|
variants: {
|
|
24
25
|
isModal: {
|
|
25
26
|
true: {
|
|
26
|
-
paddingBottom: theme.components.bottomSheet.padding
|
|
27
|
+
paddingBottom: theme.components.bottomSheet.padding,
|
|
27
28
|
},
|
|
28
29
|
},
|
|
29
30
|
handle: {
|
|
@@ -31,7 +32,20 @@ const styles = StyleSheet.create((theme, rt) => ({
|
|
|
31
32
|
paddingTop: theme.components.bottomSheet.padding,
|
|
32
33
|
},
|
|
33
34
|
},
|
|
35
|
+
useSafeAreaInsets: {
|
|
36
|
+
true: {},
|
|
37
|
+
false: {},
|
|
38
|
+
},
|
|
34
39
|
},
|
|
40
|
+
compoundVariants: [
|
|
41
|
+
{
|
|
42
|
+
isModal: true,
|
|
43
|
+
useSafeAreaInsets: true,
|
|
44
|
+
styles: {
|
|
45
|
+
paddingBottom: theme.components.bottomSheet.padding + rt.insets.bottom,
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
],
|
|
35
49
|
},
|
|
36
50
|
}));
|
|
37
51
|
BottomSheetScrollView.displayName = 'BottomSheetScrollView';
|
|
@@ -4,10 +4,11 @@ import { StyleSheet, withUnistyles } from 'react-native-unistyles';
|
|
|
4
4
|
import { useBottomSheetContext } from './BottomSheet.context';
|
|
5
5
|
const StyledBottomSheetView = withUnistyles(View);
|
|
6
6
|
const BottomSheetView = ({ children, style, isModal = true, ...props }) => {
|
|
7
|
-
const { handle } = useBottomSheetContext();
|
|
7
|
+
const { handle, useSafeAreaInsets } = useBottomSheetContext();
|
|
8
8
|
styles.useVariants({
|
|
9
9
|
isModal,
|
|
10
10
|
handle,
|
|
11
|
+
useSafeAreaInsets,
|
|
11
12
|
});
|
|
12
13
|
return (_jsx(StyledBottomSheetView, { style: [styles.contentContainer, style], ...props, children: children }));
|
|
13
14
|
};
|
|
@@ -21,7 +22,7 @@ const styles = StyleSheet.create((theme, rt) => ({
|
|
|
21
22
|
variants: {
|
|
22
23
|
isModal: {
|
|
23
24
|
true: {
|
|
24
|
-
paddingBottom: theme.components.bottomSheet.padding
|
|
25
|
+
paddingBottom: theme.components.bottomSheet.padding,
|
|
25
26
|
},
|
|
26
27
|
},
|
|
27
28
|
handle: {
|
|
@@ -29,7 +30,20 @@ const styles = StyleSheet.create((theme, rt) => ({
|
|
|
29
30
|
paddingTop: theme.components.bottomSheet.padding,
|
|
30
31
|
},
|
|
31
32
|
},
|
|
33
|
+
useSafeAreaInsets: {
|
|
34
|
+
true: {},
|
|
35
|
+
false: {},
|
|
36
|
+
},
|
|
32
37
|
},
|
|
38
|
+
compoundVariants: [
|
|
39
|
+
{
|
|
40
|
+
isModal: true,
|
|
41
|
+
useSafeAreaInsets: true,
|
|
42
|
+
styles: {
|
|
43
|
+
paddingBottom: theme.components.bottomSheet.padding + rt.insets.bottom,
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
],
|
|
33
47
|
},
|
|
34
48
|
}));
|
|
35
49
|
BottomSheetView.displayName = 'BottomSheetView';
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
export { BottomSheetFlashList, BottomSheetFooter,
|
|
1
|
+
export { BottomSheetFlashList, BottomSheetFooter, BottomSheetSectionList, BottomSheetVirtualizedList, useBottomSheet, useBottomSheetModal, type BottomSheetBackdropProps, type BottomSheetBackgroundProps, type BottomSheetHandleProps, type BottomSheetModalProps, } from '@gorhom/bottom-sheet';
|
|
2
2
|
export { default as BottomSheet } from './BottomSheet';
|
|
3
3
|
export type { default as BottomSheetProps } from './BottomSheet.props';
|
|
4
4
|
export { default as BottomSheetFlatList } from './BottomSheetFlatList';
|
|
5
5
|
export { default as BottomSheetModal } from './BottomSheetModal';
|
|
6
|
+
export { default as BottomSheetModalProvider } from './BottomSheetModalProvider';
|
|
7
|
+
export type { BottomSheetModalProviderProps } from './BottomSheetModalProvider';
|
|
6
8
|
export { default as BottomSheetScrollView } from './BottomSheetScrollView';
|
|
7
9
|
export { default as BottomSheetView } from './BottomSheetView';
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
export { BottomSheetFlashList, BottomSheetFooter,
|
|
1
|
+
export { BottomSheetFlashList, BottomSheetFooter, BottomSheetSectionList, BottomSheetVirtualizedList, useBottomSheet, useBottomSheetModal, } from '@gorhom/bottom-sheet';
|
|
2
2
|
export { default as BottomSheet } from './BottomSheet';
|
|
3
3
|
export { default as BottomSheetFlatList } from './BottomSheetFlatList';
|
|
4
4
|
export { default as BottomSheetModal } from './BottomSheetModal';
|
|
5
|
+
export { default as BottomSheetModalProvider } from './BottomSheetModalProvider';
|
|
5
6
|
export { default as BottomSheetScrollView } from './BottomSheetScrollView';
|
|
6
7
|
export { default as BottomSheetView } from './BottomSheetView';
|
|
@@ -7,6 +7,7 @@ import { StyleSheet } from 'react-native-unistyles';
|
|
|
7
7
|
import { useTheme } from '../../hooks';
|
|
8
8
|
import { BodyText } from '../BodyText';
|
|
9
9
|
import { BottomSheetFlatList, BottomSheetModal, BottomSheetView } from '../BottomSheet';
|
|
10
|
+
import { useBottomSheetContext } from '../BottomSheet/BottomSheet.context';
|
|
10
11
|
import { DetailText } from '../DetailText';
|
|
11
12
|
import { FormField, useFormFieldContext } from '../FormField';
|
|
12
13
|
import { Icon } from '../Icon';
|
|
@@ -23,6 +24,7 @@ const Combobox = ({ options = [], value, onValueChange, inputValue, onInputValue
|
|
|
23
24
|
const isDisabled = formFieldContext?.disabled ?? disabled;
|
|
24
25
|
const isReadonly = formFieldContext?.readonly ?? readonly;
|
|
25
26
|
const { color } = useTheme();
|
|
27
|
+
const { useSafeAreaInsets } = useBottomSheetContext();
|
|
26
28
|
const bottomSheetModalRef = useRef(null);
|
|
27
29
|
const searchInputRef = useRef(null);
|
|
28
30
|
const focusTimeoutRef = useRef(null);
|
|
@@ -162,7 +164,7 @@ const Combobox = ({ options = [], value, onValueChange, inputValue, onInputValue
|
|
|
162
164
|
selectedValue: value,
|
|
163
165
|
selectOption,
|
|
164
166
|
setSearch,
|
|
165
|
-
}, children: [_jsxs(SafeAreaView, { edges: ['top'], children: [menuHeading && (_jsx(View, { style: styles.headingContainer, children: _jsx(DetailText, { size: "lg", children: menuHeading }) })), _jsx(View, { style: styles.searchContainer, children: _jsx(Input, { ref: searchInputRef, placeholder: searchPlaceholder, value: search, inBottomSheet: true, onChangeText: setSearch, type: "search", clearable: true, onClear: handleClear, loading: loading }) })] }), customContent || (_jsx(BottomSheetFlatList, { data: filteredOptions, keyExtractor: (option) => option.value, renderItem: renderSelectOption, ListEmptyComponent: renderEmptyComponent, ...listProps }))] }) })] }));
|
|
167
|
+
}, children: [_jsxs(SafeAreaView, { edges: useSafeAreaInsets ? ['top'] : [], children: [menuHeading && (_jsx(View, { style: styles.headingContainer, children: _jsx(DetailText, { size: "lg", children: menuHeading }) })), _jsx(View, { style: styles.searchContainer, children: _jsx(Input, { ref: searchInputRef, placeholder: searchPlaceholder, value: search, inBottomSheet: true, onChangeText: setSearch, type: "search", clearable: true, onClear: handleClear, loading: loading }) })] }), customContent || (_jsx(BottomSheetFlatList, { data: filteredOptions, keyExtractor: (option) => option.value, renderItem: renderSelectOption, ListEmptyComponent: renderEmptyComponent, ...listProps }))] }) })] }));
|
|
166
168
|
};
|
|
167
169
|
const styles = StyleSheet.create(theme => ({
|
|
168
170
|
container: {
|
|
@@ -6,6 +6,7 @@ import { AccessibilityInfo, Platform, View, findNodeHandle } from 'react-native'
|
|
|
6
6
|
import { StyleSheet } from 'react-native-unistyles';
|
|
7
7
|
import { BodyText } from '../BodyText';
|
|
8
8
|
import { BottomSheetModal, BottomSheetScrollView } from '../BottomSheet';
|
|
9
|
+
import { useBottomSheetContext } from '../BottomSheet/BottomSheet.context';
|
|
9
10
|
import { Button } from '../Button';
|
|
10
11
|
import { Heading } from '../Heading';
|
|
11
12
|
import { Spinner } from '../Spinner';
|
|
@@ -14,6 +15,7 @@ const Modal = ({ ref, children, heading, description, showCloseButton = true, pr
|
|
|
14
15
|
const bottomSheetModalRef = useRef(null);
|
|
15
16
|
const viewRef = useRef(null);
|
|
16
17
|
const scrollViewRef = useRef(null);
|
|
18
|
+
const { useSafeAreaInsets } = useBottomSheetContext();
|
|
17
19
|
useImperativeHandle(ref, () => ({
|
|
18
20
|
...bottomSheetModalRef.current,
|
|
19
21
|
}));
|
|
@@ -64,6 +66,7 @@ const Modal = ({ ref, children, heading, description, showCloseButton = true, pr
|
|
|
64
66
|
noButtons,
|
|
65
67
|
stickyFooter,
|
|
66
68
|
showHandle: props.showHandle,
|
|
69
|
+
useSafeAreaInsets,
|
|
67
70
|
});
|
|
68
71
|
const footer = useMemo(() => (_jsxs(View, { style: styles.footer, children: [onPressPrimaryButton && primaryButtonText ? (_jsx(Button, { onPress: handlePrimaryButtonPress, text: primaryButtonText, ...primaryButtonProps, variant: primaryButtonProps?.variant ?? 'solid', colorScheme: primaryButtonProps?.colorScheme ?? 'highlight' })) : null, onPressSecondaryButton && secondaryButtonText ? (_jsx(Button, { onPress: handleSecondaryButtonPress, text: secondaryButtonText, ...secondaryButtonProps, variant: secondaryButtonProps?.variant ?? 'outline', colorScheme: secondaryButtonProps?.colorScheme ?? 'functional' })) : null] })), [
|
|
69
72
|
handlePrimaryButtonPress,
|
|
@@ -99,34 +102,68 @@ const styles = StyleSheet.create((theme, rt) => ({
|
|
|
99
102
|
variants: {
|
|
100
103
|
bothButtons: {
|
|
101
104
|
true: {
|
|
105
|
+
paddingBottom: 166,
|
|
106
|
+
},
|
|
107
|
+
false: {
|
|
108
|
+
paddingBottom: 102,
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
noButtons: {
|
|
112
|
+
true: {
|
|
113
|
+
paddingBottom: theme.components.modal.padding,
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
stickyFooter: {
|
|
117
|
+
true: {},
|
|
118
|
+
false: {
|
|
119
|
+
paddingBottom: theme.components.modal.padding + theme.components.bottomSheet.padding,
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
useSafeAreaInsets: {
|
|
123
|
+
true: {},
|
|
124
|
+
false: {},
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
compoundVariants: [
|
|
128
|
+
{
|
|
129
|
+
bothButtons: true,
|
|
130
|
+
useSafeAreaInsets: true,
|
|
131
|
+
styles: {
|
|
102
132
|
paddingBottom: 166 +
|
|
103
133
|
rt.insets.bottom -
|
|
104
134
|
theme.components.modal.padding +
|
|
105
135
|
theme.components.bottomSheet.padding,
|
|
106
136
|
},
|
|
107
|
-
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
bothButtons: false,
|
|
140
|
+
useSafeAreaInsets: true,
|
|
141
|
+
styles: {
|
|
108
142
|
paddingBottom: 102 +
|
|
109
143
|
rt.insets.bottom -
|
|
110
144
|
theme.components.modal.padding +
|
|
111
145
|
theme.components.bottomSheet.padding,
|
|
112
146
|
},
|
|
113
147
|
},
|
|
114
|
-
|
|
115
|
-
|
|
148
|
+
{
|
|
149
|
+
noButtons: true,
|
|
150
|
+
useSafeAreaInsets: true,
|
|
151
|
+
styles: {
|
|
116
152
|
paddingBottom: rt.insets.bottom +
|
|
117
153
|
theme.components.modal.padding +
|
|
118
154
|
theme.components.bottomSheet.padding,
|
|
119
155
|
},
|
|
120
156
|
},
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
157
|
+
{
|
|
158
|
+
useSafeAreaInsets: true,
|
|
159
|
+
stickyFooter: false,
|
|
160
|
+
styles: {
|
|
124
161
|
paddingBottom: rt.insets.bottom +
|
|
125
162
|
theme.components.modal.padding +
|
|
126
163
|
theme.components.bottomSheet.padding,
|
|
127
164
|
},
|
|
128
165
|
},
|
|
129
|
-
|
|
166
|
+
],
|
|
130
167
|
},
|
|
131
168
|
header: {
|
|
132
169
|
flexDirection: 'row',
|
|
@@ -172,7 +209,16 @@ const styles = StyleSheet.create((theme, rt) => ({
|
|
|
172
209
|
footerWrap: {
|
|
173
210
|
backgroundColor: theme.color.surface.neutral.strong,
|
|
174
211
|
paddingHorizontal: theme.components.bottomSheet.padding,
|
|
175
|
-
|
|
212
|
+
variants: {
|
|
213
|
+
useSafeAreaInsets: {
|
|
214
|
+
true: {
|
|
215
|
+
paddingBottom: theme.components.bottomSheet.padding + rt.insets.bottom,
|
|
216
|
+
},
|
|
217
|
+
false: {
|
|
218
|
+
paddingBottom: theme.components.bottomSheet.padding,
|
|
219
|
+
},
|
|
220
|
+
},
|
|
221
|
+
},
|
|
176
222
|
},
|
|
177
223
|
}));
|
|
178
224
|
export default Modal;
|
|
@@ -152,7 +152,9 @@ const styles = StyleSheet.create((theme, rt) => ({
|
|
|
152
152
|
flex: 1,
|
|
153
153
|
variants: {
|
|
154
154
|
background: {
|
|
155
|
-
primary: {
|
|
155
|
+
primary: {
|
|
156
|
+
backgroundColor: theme.color.surface.neutral.strong,
|
|
157
|
+
},
|
|
156
158
|
brand: {
|
|
157
159
|
backgroundColor: theme.color.background.brand,
|
|
158
160
|
},
|
|
@@ -161,11 +163,9 @@ const styles = StyleSheet.create((theme, rt) => ({
|
|
|
161
163
|
modal: {
|
|
162
164
|
borderTopLeftRadius: theme.components.modal.borderRadius,
|
|
163
165
|
borderTopRightRadius: theme.components.modal.borderRadius,
|
|
164
|
-
backgroundColor: theme.color.surface.neutral.strong,
|
|
165
166
|
padding: theme.components.bottomSheet.padding,
|
|
166
167
|
},
|
|
167
168
|
fullScreen: {
|
|
168
|
-
backgroundColor: theme.color.surface.neutral.strong,
|
|
169
169
|
padding: theme.components.bottomSheet.padding,
|
|
170
170
|
},
|
|
171
171
|
},
|
|
@@ -6,6 +6,7 @@ import { SafeAreaView } from 'react-native-safe-area-context';
|
|
|
6
6
|
import { StyleSheet } from 'react-native-unistyles';
|
|
7
7
|
import { BodyText } from '../BodyText';
|
|
8
8
|
import { BottomSheetFlatList, BottomSheetModal, BottomSheetScrollView, BottomSheetView, } from '../BottomSheet';
|
|
9
|
+
import { useBottomSheetContext } from '../BottomSheet/BottomSheet.context';
|
|
9
10
|
import { DetailText } from '../DetailText';
|
|
10
11
|
import { FormField, useFormFieldContext } from '../FormField';
|
|
11
12
|
import { Icon } from '../Icon';
|
|
@@ -18,6 +19,7 @@ const Select = ({ options = [], value, onValueChange, label, labelVariant = 'bod
|
|
|
18
19
|
const isRequired = formFieldContext?.required ?? required;
|
|
19
20
|
const isDisabled = formFieldContext?.disabled ?? disabled;
|
|
20
21
|
const isReadonly = formFieldContext?.readonly ?? readonly;
|
|
22
|
+
const { useSafeAreaInsets } = useBottomSheetContext();
|
|
21
23
|
const bottomSheetModalRef = useRef(null);
|
|
22
24
|
const [search, setSearch] = useState('');
|
|
23
25
|
const [isOpen, setIsOpen] = useState(false);
|
|
@@ -77,7 +79,7 @@ const Select = ({ options = [], value, onValueChange, label, labelVariant = 'bod
|
|
|
77
79
|
selectedValue: value,
|
|
78
80
|
onValueChange,
|
|
79
81
|
close: closeBottomSheet,
|
|
80
|
-
}, children: _jsxs(SafeAreaView, { edges: ['top'], style: { flex: 1 }, children: [menuHeading && (_jsx(View, { style: styles.headingContainer, children: _jsx(DetailText, { size: "lg", children: menuHeading }) })), searchable && (_jsx(View, { style: styles.searchContainer, children: _jsx(Input, { placeholder: searchPlaceholder, value: search, inBottomSheet: true, onChangeText: setSearch, type: "search", testID: testID ? `${testID}-search` : undefined }) })), children ? (_jsx(BottomSheetScrollView, { testID: testID ? `${testID}-options` : undefined, children: children })) : (_jsx(BottomSheetFlatList, { data: filteredOptions, keyExtractor: (option) => option.value, renderItem: renderSelectOption, ListEmptyComponent: renderEmptyComponent, testID: testID ? `${testID}-options` : undefined, ...listProps }))] }) }) })] }));
|
|
82
|
+
}, children: _jsxs(SafeAreaView, { edges: useSafeAreaInsets ? ['top'] : [], style: { flex: 1 }, children: [menuHeading && (_jsx(View, { style: styles.headingContainer, children: _jsx(DetailText, { size: "lg", children: menuHeading }) })), searchable && (_jsx(View, { style: styles.searchContainer, children: _jsx(Input, { placeholder: searchPlaceholder, value: search, inBottomSheet: true, onChangeText: setSearch, type: "search", testID: testID ? `${testID}-search` : undefined }) })), children ? (_jsx(BottomSheetScrollView, { testID: testID ? `${testID}-options` : undefined, children: children })) : (_jsx(BottomSheetFlatList, { data: filteredOptions, keyExtractor: (option) => option.value, renderItem: renderSelectOption, ListEmptyComponent: renderEmptyComponent, testID: testID ? `${testID}-options` : undefined, ...listProps }))] }) }) })] }));
|
|
81
83
|
};
|
|
82
84
|
const styles = StyleSheet.create(theme => ({
|
|
83
85
|
container: {
|
package/package.json
CHANGED
|
@@ -2,9 +2,12 @@ import { createContext, useContext } from 'react';
|
|
|
2
2
|
|
|
3
3
|
interface BottomSheetContextProps {
|
|
4
4
|
handle?: boolean;
|
|
5
|
+
useSafeAreaInsets: boolean;
|
|
5
6
|
}
|
|
6
7
|
|
|
7
|
-
export const BottomSheetContext = createContext<BottomSheetContextProps>({
|
|
8
|
+
export const BottomSheetContext = createContext<BottomSheetContextProps>({
|
|
9
|
+
useSafeAreaInsets: true,
|
|
10
|
+
});
|
|
8
11
|
|
|
9
12
|
export const useBottomSheetContext = (): BottomSheetContextProps => {
|
|
10
13
|
const context = useContext(BottomSheetContext);
|
|
@@ -129,6 +129,20 @@ const App = () => {
|
|
|
129
129
|
};
|
|
130
130
|
```
|
|
131
131
|
|
|
132
|
+
`BottomSheetModalProvider` adds Hearth's bottom-sheet safe-area spacing by default. If your app already handles safe-area padding, you can opt out and avoid double spacing:
|
|
133
|
+
|
|
134
|
+
```tsx
|
|
135
|
+
import { BottomSheetModalProvider } from '@utilitywarehouse/hearth-react-native';
|
|
136
|
+
|
|
137
|
+
const App = () => {
|
|
138
|
+
return (
|
|
139
|
+
<BottomSheetModalProvider useSafeAreaInsets={false}>
|
|
140
|
+
{/* Your app content */}
|
|
141
|
+
</BottomSheetModalProvider>
|
|
142
|
+
);
|
|
143
|
+
};
|
|
144
|
+
```
|
|
145
|
+
|
|
132
146
|
### `BottomSheetScrollView`
|
|
133
147
|
|
|
134
148
|
For scrollable content within a bottom sheet, use the `BottomSheetScrollView` component instead of the standard ScrollView:
|
|
@@ -169,6 +183,12 @@ const App = () => {
|
|
|
169
183
|
};
|
|
170
184
|
```
|
|
171
185
|
|
|
186
|
+
Use the `useSafeAreaInsets` prop to control whether Hearth applies bottom-sheet safe-area spacing for modal content, list wrappers, and the top `SafeAreaView` used by components such as `Select` and `Combobox`.
|
|
187
|
+
|
|
188
|
+
| Property | Type | Description | Default |
|
|
189
|
+
| ------------------- | --------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | ------- |
|
|
190
|
+
| `useSafeAreaInsets` | `boolean` | Applies Hearth's safe-area insets inside bottom sheets. Set to `false` when your app already manages safe-area padding around bottom-sheet content. | `true` |
|
|
191
|
+
|
|
172
192
|
### `Input` in Bottom Sheets
|
|
173
193
|
|
|
174
194
|
When using the `Input` component inside a `BottomSheet` or `BottomSheetModal`, you need to pass the `inBottomSheet` prop to ensure proper behavior with the keyboard and focus management.
|
|
@@ -22,6 +22,7 @@ const BottomSheet = ({
|
|
|
22
22
|
...rest
|
|
23
23
|
}: BottomSheetProps) => {
|
|
24
24
|
const bottomSheetRef = React.useRef<BottomSheet>(null);
|
|
25
|
+
const parentContext = React.useContext(BottomSheetContext);
|
|
25
26
|
|
|
26
27
|
const { renderBackdrop, renderHandle } = useBottomSheetLogic<BottomSheet>({
|
|
27
28
|
ref,
|
|
@@ -31,7 +32,13 @@ const BottomSheet = ({
|
|
|
31
32
|
handleStyle,
|
|
32
33
|
});
|
|
33
34
|
|
|
34
|
-
const value = useMemo(
|
|
35
|
+
const value = useMemo(
|
|
36
|
+
() => ({
|
|
37
|
+
...parentContext,
|
|
38
|
+
handle: showHandle,
|
|
39
|
+
}),
|
|
40
|
+
[parentContext, showHandle]
|
|
41
|
+
);
|
|
35
42
|
|
|
36
43
|
return (
|
|
37
44
|
<StyledBottomSheetCore
|
|
@@ -11,10 +11,11 @@ const BottomSheetFlatList = ({
|
|
|
11
11
|
isModal = true,
|
|
12
12
|
...props
|
|
13
13
|
}: BottomSheetFlatListProps<any> & { isModal?: boolean }) => {
|
|
14
|
-
const { handle } = useBottomSheetContext();
|
|
14
|
+
const { handle, useSafeAreaInsets } = useBottomSheetContext();
|
|
15
15
|
styles.useVariants({
|
|
16
16
|
isModal,
|
|
17
17
|
handle,
|
|
18
|
+
useSafeAreaInsets,
|
|
18
19
|
});
|
|
19
20
|
|
|
20
21
|
return (
|
|
@@ -34,7 +35,7 @@ const styles = StyleSheet.create((theme, rt) => ({
|
|
|
34
35
|
variants: {
|
|
35
36
|
isModal: {
|
|
36
37
|
true: {
|
|
37
|
-
paddingBottom: theme.components.bottomSheet.padding
|
|
38
|
+
paddingBottom: theme.components.bottomSheet.padding,
|
|
38
39
|
},
|
|
39
40
|
},
|
|
40
41
|
handle: {
|
|
@@ -42,7 +43,20 @@ const styles = StyleSheet.create((theme, rt) => ({
|
|
|
42
43
|
paddingTop: theme.components.bottomSheet.padding,
|
|
43
44
|
},
|
|
44
45
|
},
|
|
46
|
+
useSafeAreaInsets: {
|
|
47
|
+
true: {},
|
|
48
|
+
false: {},
|
|
49
|
+
},
|
|
45
50
|
},
|
|
51
|
+
compoundVariants: [
|
|
52
|
+
{
|
|
53
|
+
isModal: true,
|
|
54
|
+
useSafeAreaInsets: true,
|
|
55
|
+
styles: {
|
|
56
|
+
paddingBottom: theme.components.bottomSheet.padding + rt.insets.bottom,
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
],
|
|
46
60
|
},
|
|
47
61
|
}));
|
|
48
62
|
|
|
@@ -20,6 +20,7 @@ const BottomSheetModal = ({
|
|
|
20
20
|
...rest
|
|
21
21
|
}: BottomSheetProps) => {
|
|
22
22
|
const bottomSheetRef = React.useRef<BottomSheetModalMethods<any>>(null);
|
|
23
|
+
const parentContext = React.useContext(BottomSheetContext);
|
|
23
24
|
|
|
24
25
|
const { renderBackdrop, renderHandle } = useBottomSheetLogic<BottomSheetModal>({
|
|
25
26
|
// @ts-expect-error - ref
|
|
@@ -30,7 +31,13 @@ const BottomSheetModal = ({
|
|
|
30
31
|
handleStyle,
|
|
31
32
|
});
|
|
32
33
|
|
|
33
|
-
const value = useMemo(
|
|
34
|
+
const value = useMemo(
|
|
35
|
+
() => ({
|
|
36
|
+
...parentContext,
|
|
37
|
+
handle: showHandle,
|
|
38
|
+
}),
|
|
39
|
+
[parentContext, showHandle]
|
|
40
|
+
);
|
|
34
41
|
|
|
35
42
|
return (
|
|
36
43
|
<StyledBottomSheetModalCore
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { BottomSheetModalProvider as GorhomBottomSheetModalProvider } from '@gorhom/bottom-sheet';
|
|
2
|
+
import type { BottomSheetModalProviderProps as GorhomBottomSheetModalProviderProps } from '@gorhom/bottom-sheet/lib/typescript/components/bottomSheetModalProvider/types';
|
|
3
|
+
import { useMemo } from 'react';
|
|
4
|
+
import { BottomSheetContext, useBottomSheetContext } from './BottomSheet.context';
|
|
5
|
+
|
|
6
|
+
export interface BottomSheetModalProviderProps extends GorhomBottomSheetModalProviderProps {
|
|
7
|
+
useSafeAreaInsets?: boolean;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const BottomSheetModalProvider = ({
|
|
11
|
+
children,
|
|
12
|
+
useSafeAreaInsets = true,
|
|
13
|
+
...props
|
|
14
|
+
}: BottomSheetModalProviderProps) => {
|
|
15
|
+
const parentContext = useBottomSheetContext();
|
|
16
|
+
const value = useMemo(
|
|
17
|
+
() => ({
|
|
18
|
+
...parentContext,
|
|
19
|
+
useSafeAreaInsets,
|
|
20
|
+
}),
|
|
21
|
+
[parentContext, useSafeAreaInsets]
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
<GorhomBottomSheetModalProvider {...props}>
|
|
26
|
+
<BottomSheetContext.Provider value={value}>{children}</BottomSheetContext.Provider>
|
|
27
|
+
</GorhomBottomSheetModalProvider>
|
|
28
|
+
);
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
BottomSheetModalProvider.displayName = 'BottomSheetModalProvider';
|
|
32
|
+
|
|
33
|
+
export default BottomSheetModalProvider;
|
|
@@ -14,10 +14,11 @@ const BottomSheetScrollView = ({
|
|
|
14
14
|
isModal = true,
|
|
15
15
|
...props
|
|
16
16
|
}: BottomSheetScrollViewProps & { isModal?: boolean }) => {
|
|
17
|
-
const { handle } = useBottomSheetContext();
|
|
17
|
+
const { handle, useSafeAreaInsets } = useBottomSheetContext();
|
|
18
18
|
styles.useVariants({
|
|
19
19
|
isModal,
|
|
20
20
|
handle,
|
|
21
|
+
useSafeAreaInsets,
|
|
21
22
|
});
|
|
22
23
|
|
|
23
24
|
return (
|
|
@@ -43,7 +44,7 @@ const styles = StyleSheet.create((theme, rt) => ({
|
|
|
43
44
|
variants: {
|
|
44
45
|
isModal: {
|
|
45
46
|
true: {
|
|
46
|
-
paddingBottom: theme.components.bottomSheet.padding
|
|
47
|
+
paddingBottom: theme.components.bottomSheet.padding,
|
|
47
48
|
},
|
|
48
49
|
},
|
|
49
50
|
handle: {
|
|
@@ -51,7 +52,20 @@ const styles = StyleSheet.create((theme, rt) => ({
|
|
|
51
52
|
paddingTop: theme.components.bottomSheet.padding,
|
|
52
53
|
},
|
|
53
54
|
},
|
|
55
|
+
useSafeAreaInsets: {
|
|
56
|
+
true: {},
|
|
57
|
+
false: {},
|
|
58
|
+
},
|
|
54
59
|
},
|
|
60
|
+
compoundVariants: [
|
|
61
|
+
{
|
|
62
|
+
isModal: true,
|
|
63
|
+
useSafeAreaInsets: true,
|
|
64
|
+
styles: {
|
|
65
|
+
paddingBottom: theme.components.bottomSheet.padding + rt.insets.bottom,
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
],
|
|
55
69
|
},
|
|
56
70
|
}));
|
|
57
71
|
|
|
@@ -13,11 +13,13 @@ const BottomSheetView = ({
|
|
|
13
13
|
isModal = true,
|
|
14
14
|
...props
|
|
15
15
|
}: BottomSheetViewProps & { isModal?: boolean }) => {
|
|
16
|
-
const { handle } = useBottomSheetContext();
|
|
16
|
+
const { handle, useSafeAreaInsets } = useBottomSheetContext();
|
|
17
17
|
styles.useVariants({
|
|
18
18
|
isModal,
|
|
19
19
|
handle,
|
|
20
|
+
useSafeAreaInsets,
|
|
20
21
|
});
|
|
22
|
+
|
|
21
23
|
return (
|
|
22
24
|
<StyledBottomSheetView style={[styles.contentContainer, style]} {...props}>
|
|
23
25
|
{children}
|
|
@@ -35,7 +37,7 @@ const styles = StyleSheet.create((theme, rt) => ({
|
|
|
35
37
|
variants: {
|
|
36
38
|
isModal: {
|
|
37
39
|
true: {
|
|
38
|
-
paddingBottom: theme.components.bottomSheet.padding
|
|
40
|
+
paddingBottom: theme.components.bottomSheet.padding,
|
|
39
41
|
},
|
|
40
42
|
},
|
|
41
43
|
handle: {
|
|
@@ -43,7 +45,20 @@ const styles = StyleSheet.create((theme, rt) => ({
|
|
|
43
45
|
paddingTop: theme.components.bottomSheet.padding,
|
|
44
46
|
},
|
|
45
47
|
},
|
|
48
|
+
useSafeAreaInsets: {
|
|
49
|
+
true: {},
|
|
50
|
+
false: {},
|
|
51
|
+
},
|
|
46
52
|
},
|
|
53
|
+
compoundVariants: [
|
|
54
|
+
{
|
|
55
|
+
isModal: true,
|
|
56
|
+
useSafeAreaInsets: true,
|
|
57
|
+
styles: {
|
|
58
|
+
paddingBottom: theme.components.bottomSheet.padding + rt.insets.bottom,
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
],
|
|
47
62
|
},
|
|
48
63
|
}));
|
|
49
64
|
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
export {
|
|
2
2
|
BottomSheetFlashList,
|
|
3
3
|
BottomSheetFooter,
|
|
4
|
-
BottomSheetModalProvider,
|
|
5
4
|
BottomSheetSectionList,
|
|
6
5
|
BottomSheetVirtualizedList,
|
|
7
6
|
useBottomSheet,
|
|
@@ -15,5 +14,7 @@ export { default as BottomSheet } from './BottomSheet';
|
|
|
15
14
|
export type { default as BottomSheetProps } from './BottomSheet.props';
|
|
16
15
|
export { default as BottomSheetFlatList } from './BottomSheetFlatList';
|
|
17
16
|
export { default as BottomSheetModal } from './BottomSheetModal';
|
|
17
|
+
export { default as BottomSheetModalProvider } from './BottomSheetModalProvider';
|
|
18
|
+
export type { BottomSheetModalProviderProps } from './BottomSheetModalProvider';
|
|
18
19
|
export { default as BottomSheetScrollView } from './BottomSheetScrollView';
|
|
19
20
|
export { default as BottomSheetView } from './BottomSheetView';
|
|
@@ -6,6 +6,7 @@ import { StyleSheet } from 'react-native-unistyles';
|
|
|
6
6
|
import { useTheme } from '../../hooks';
|
|
7
7
|
import { BodyText } from '../BodyText';
|
|
8
8
|
import { BottomSheetFlatList, BottomSheetModal, BottomSheetView } from '../BottomSheet';
|
|
9
|
+
import { useBottomSheetContext } from '../BottomSheet/BottomSheet.context';
|
|
9
10
|
import { DetailText } from '../DetailText';
|
|
10
11
|
import { FormField, useFormFieldContext } from '../FormField';
|
|
11
12
|
import { Icon } from '../Icon';
|
|
@@ -55,6 +56,7 @@ const Combobox = ({
|
|
|
55
56
|
const isDisabled = formFieldContext?.disabled ?? disabled;
|
|
56
57
|
const isReadonly = formFieldContext?.readonly ?? readonly;
|
|
57
58
|
const { color } = useTheme();
|
|
59
|
+
const { useSafeAreaInsets } = useBottomSheetContext();
|
|
58
60
|
|
|
59
61
|
const bottomSheetModalRef = useRef<BottomSheetModal>(null);
|
|
60
62
|
const searchInputRef = useRef<TextInput>(null);
|
|
@@ -325,7 +327,7 @@ const Combobox = ({
|
|
|
325
327
|
setSearch,
|
|
326
328
|
}}
|
|
327
329
|
>
|
|
328
|
-
<SafeAreaView edges={['top']}>
|
|
330
|
+
<SafeAreaView edges={useSafeAreaInsets ? ['top'] : []}>
|
|
329
331
|
{menuHeading && (
|
|
330
332
|
<View style={styles.headingContainer}>
|
|
331
333
|
<DetailText size="lg">{menuHeading}</DetailText>
|
|
@@ -476,6 +476,20 @@ const App = () => {
|
|
|
476
476
|
};
|
|
477
477
|
```
|
|
478
478
|
|
|
479
|
+
If your app already handles safe-area padding around modal content, you can disable Hearth's bottom-sheet safe-area spacing:
|
|
480
|
+
|
|
481
|
+
```tsx
|
|
482
|
+
import { BottomSheetModalProvider } from '@utilitywarehouse/hearth-react-native';
|
|
483
|
+
|
|
484
|
+
const App = () => {
|
|
485
|
+
return (
|
|
486
|
+
<BottomSheetModalProvider useSafeAreaInsets={false}>
|
|
487
|
+
{/* Your app content */}
|
|
488
|
+
</BottomSheetModalProvider>
|
|
489
|
+
);
|
|
490
|
+
};
|
|
491
|
+
```
|
|
492
|
+
|
|
479
493
|
### Ref Usage
|
|
480
494
|
|
|
481
495
|
The Modal component forwards its ref to the underlying `BottomSheetModal`, giving you access to methods like:
|
|
@@ -11,6 +11,7 @@ import { AccessibilityInfo, Platform, View, findNodeHandle } from 'react-native'
|
|
|
11
11
|
import { StyleSheet } from 'react-native-unistyles';
|
|
12
12
|
import { BodyText } from '../BodyText';
|
|
13
13
|
import { BottomSheetModal, BottomSheetScrollView } from '../BottomSheet';
|
|
14
|
+
import { useBottomSheetContext } from '../BottomSheet/BottomSheet.context';
|
|
14
15
|
import { Button } from '../Button';
|
|
15
16
|
import { Heading } from '../Heading';
|
|
16
17
|
import { Spinner } from '../Spinner';
|
|
@@ -45,6 +46,7 @@ const Modal = ({
|
|
|
45
46
|
const bottomSheetModalRef = useRef<BottomSheetModal>(null);
|
|
46
47
|
const viewRef = useRef<View>(null);
|
|
47
48
|
const scrollViewRef = useRef<BottomSheetScrollViewMethods>(null);
|
|
49
|
+
const { useSafeAreaInsets } = useBottomSheetContext();
|
|
48
50
|
|
|
49
51
|
useImperativeHandle(ref, () => ({
|
|
50
52
|
...(bottomSheetModalRef.current as BottomSheetModal),
|
|
@@ -105,6 +107,7 @@ const Modal = ({
|
|
|
105
107
|
noButtons,
|
|
106
108
|
stickyFooter,
|
|
107
109
|
showHandle: props.showHandle,
|
|
110
|
+
useSafeAreaInsets,
|
|
108
111
|
});
|
|
109
112
|
|
|
110
113
|
const footer = useMemo(
|
|
@@ -256,13 +259,44 @@ const styles = StyleSheet.create((theme, rt) => ({
|
|
|
256
259
|
variants: {
|
|
257
260
|
bothButtons: {
|
|
258
261
|
true: {
|
|
262
|
+
paddingBottom: 166,
|
|
263
|
+
},
|
|
264
|
+
false: {
|
|
265
|
+
paddingBottom: 102,
|
|
266
|
+
},
|
|
267
|
+
},
|
|
268
|
+
noButtons: {
|
|
269
|
+
true: {
|
|
270
|
+
paddingBottom: theme.components.modal.padding,
|
|
271
|
+
},
|
|
272
|
+
},
|
|
273
|
+
stickyFooter: {
|
|
274
|
+
true: {},
|
|
275
|
+
false: {
|
|
276
|
+
paddingBottom: theme.components.modal.padding + theme.components.bottomSheet.padding,
|
|
277
|
+
},
|
|
278
|
+
},
|
|
279
|
+
useSafeAreaInsets: {
|
|
280
|
+
true: {},
|
|
281
|
+
false: {},
|
|
282
|
+
},
|
|
283
|
+
},
|
|
284
|
+
compoundVariants: [
|
|
285
|
+
{
|
|
286
|
+
bothButtons: true,
|
|
287
|
+
useSafeAreaInsets: true,
|
|
288
|
+
styles: {
|
|
259
289
|
paddingBottom:
|
|
260
290
|
166 +
|
|
261
291
|
rt.insets.bottom -
|
|
262
292
|
theme.components.modal.padding +
|
|
263
293
|
theme.components.bottomSheet.padding,
|
|
264
294
|
},
|
|
265
|
-
|
|
295
|
+
},
|
|
296
|
+
{
|
|
297
|
+
bothButtons: false,
|
|
298
|
+
useSafeAreaInsets: true,
|
|
299
|
+
styles: {
|
|
266
300
|
paddingBottom:
|
|
267
301
|
102 +
|
|
268
302
|
rt.insets.bottom -
|
|
@@ -270,24 +304,27 @@ const styles = StyleSheet.create((theme, rt) => ({
|
|
|
270
304
|
theme.components.bottomSheet.padding,
|
|
271
305
|
},
|
|
272
306
|
},
|
|
273
|
-
|
|
274
|
-
|
|
307
|
+
{
|
|
308
|
+
noButtons: true,
|
|
309
|
+
useSafeAreaInsets: true,
|
|
310
|
+
styles: {
|
|
275
311
|
paddingBottom:
|
|
276
312
|
rt.insets.bottom +
|
|
277
313
|
theme.components.modal.padding +
|
|
278
314
|
theme.components.bottomSheet.padding,
|
|
279
315
|
},
|
|
280
316
|
},
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
317
|
+
{
|
|
318
|
+
useSafeAreaInsets: true,
|
|
319
|
+
stickyFooter: false,
|
|
320
|
+
styles: {
|
|
284
321
|
paddingBottom:
|
|
285
322
|
rt.insets.bottom +
|
|
286
323
|
theme.components.modal.padding +
|
|
287
324
|
theme.components.bottomSheet.padding,
|
|
288
325
|
},
|
|
289
326
|
},
|
|
290
|
-
|
|
327
|
+
],
|
|
291
328
|
},
|
|
292
329
|
header: {
|
|
293
330
|
flexDirection: 'row',
|
|
@@ -333,7 +370,16 @@ const styles = StyleSheet.create((theme, rt) => ({
|
|
|
333
370
|
footerWrap: {
|
|
334
371
|
backgroundColor: theme.color.surface.neutral.strong,
|
|
335
372
|
paddingHorizontal: theme.components.bottomSheet.padding,
|
|
336
|
-
|
|
373
|
+
variants: {
|
|
374
|
+
useSafeAreaInsets: {
|
|
375
|
+
true: {
|
|
376
|
+
paddingBottom: theme.components.bottomSheet.padding + rt.insets.bottom,
|
|
377
|
+
},
|
|
378
|
+
false: {
|
|
379
|
+
paddingBottom: theme.components.bottomSheet.padding,
|
|
380
|
+
},
|
|
381
|
+
},
|
|
382
|
+
},
|
|
337
383
|
},
|
|
338
384
|
}));
|
|
339
385
|
|
|
@@ -336,7 +336,9 @@ const styles = StyleSheet.create((theme, rt) => ({
|
|
|
336
336
|
flex: 1,
|
|
337
337
|
variants: {
|
|
338
338
|
background: {
|
|
339
|
-
primary: {
|
|
339
|
+
primary: {
|
|
340
|
+
backgroundColor: theme.color.surface.neutral.strong,
|
|
341
|
+
},
|
|
340
342
|
brand: {
|
|
341
343
|
backgroundColor: theme.color.background.brand,
|
|
342
344
|
},
|
|
@@ -345,11 +347,9 @@ const styles = StyleSheet.create((theme, rt) => ({
|
|
|
345
347
|
modal: {
|
|
346
348
|
borderTopLeftRadius: theme.components.modal.borderRadius,
|
|
347
349
|
borderTopRightRadius: theme.components.modal.borderRadius,
|
|
348
|
-
backgroundColor: theme.color.surface.neutral.strong,
|
|
349
350
|
padding: theme.components.bottomSheet.padding,
|
|
350
351
|
},
|
|
351
352
|
fullScreen: {
|
|
352
|
-
backgroundColor: theme.color.surface.neutral.strong,
|
|
353
353
|
padding: theme.components.bottomSheet.padding,
|
|
354
354
|
},
|
|
355
355
|
},
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
BottomSheetScrollView,
|
|
11
11
|
BottomSheetView,
|
|
12
12
|
} from '../BottomSheet';
|
|
13
|
+
import { useBottomSheetContext } from '../BottomSheet/BottomSheet.context';
|
|
13
14
|
import { DetailText } from '../DetailText';
|
|
14
15
|
import { FormField, useFormFieldContext } from '../FormField';
|
|
15
16
|
import { Icon } from '../Icon';
|
|
@@ -49,6 +50,7 @@ const Select = ({
|
|
|
49
50
|
const isRequired = formFieldContext?.required ?? required;
|
|
50
51
|
const isDisabled = formFieldContext?.disabled ?? disabled;
|
|
51
52
|
const isReadonly = formFieldContext?.readonly ?? readonly;
|
|
53
|
+
const { useSafeAreaInsets } = useBottomSheetContext();
|
|
52
54
|
|
|
53
55
|
const bottomSheetModalRef = useRef<BottomSheetModal>(null);
|
|
54
56
|
const [search, setSearch] = useState('');
|
|
@@ -183,7 +185,7 @@ const Select = ({
|
|
|
183
185
|
close: closeBottomSheet,
|
|
184
186
|
}}
|
|
185
187
|
>
|
|
186
|
-
<SafeAreaView edges={['top']} style={{ flex: 1 }}>
|
|
188
|
+
<SafeAreaView edges={useSafeAreaInsets ? ['top'] : []} style={{ flex: 1 }}>
|
|
187
189
|
{menuHeading && (
|
|
188
190
|
<View style={styles.headingContainer}>
|
|
189
191
|
<DetailText size="lg">{menuHeading}</DetailText>
|