@utilitywarehouse/hearth-react-native 0.30.0 → 0.30.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 +27 -0
- package/build/components/Banner/Banner.d.ts +1 -1
- package/build/components/Banner/Banner.js +26 -2
- package/build/components/Banner/Banner.props.d.ts +5 -0
- package/build/components/NavModal/NavModal.d.ts +1 -1
- package/build/components/NavModal/NavModal.js +50 -10
- package/build/components/NavModal/NavModal.props.d.ts +3 -3
- package/docs/changelog.mdx +67 -0
- package/package.json +2 -2
- package/src/components/Banner/Banner.docs.mdx +1 -0
- package/src/components/Banner/Banner.props.ts +5 -0
- package/src/components/Banner/Banner.stories.tsx +16 -0
- package/src/components/Banner/Banner.tsx +26 -1
- package/src/components/NavModal/NavModal.docs.mdx +24 -24
- package/src/components/NavModal/NavModal.props.ts +3 -3
- package/src/components/NavModal/NavModal.tsx +51 -15
package/.turbo/turbo-build.log
CHANGED
package/.turbo/turbo-lint.log
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
> @utilitywarehouse/hearth-react-native@0.30.
|
|
2
|
+
> @utilitywarehouse/hearth-react-native@0.30.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
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
no-
|
|
63
|
-
no-
|
|
64
|
-
@typescript-eslint/no-
|
|
65
|
-
no-
|
|
54
|
+
Rule | Time (ms) | Relative
|
|
55
|
+
:-------------------------------------------------|----------:|--------:
|
|
56
|
+
@typescript-eslint/no-unused-vars | 1495.988 | 61.0%
|
|
57
|
+
react-hooks/exhaustive-deps | 86.813 | 3.5%
|
|
58
|
+
no-global-assign | 85.050 | 3.5%
|
|
59
|
+
react-hooks/rules-of-hooks | 60.522 | 2.5%
|
|
60
|
+
@typescript-eslint/ban-ts-comment | 49.138 | 2.0%
|
|
61
|
+
no-unexpected-multiline | 46.592 | 1.9%
|
|
62
|
+
no-useless-escape | 39.187 | 1.6%
|
|
63
|
+
no-misleading-character-class | 35.552 | 1.5%
|
|
64
|
+
@typescript-eslint/no-unused-expressions | 33.343 | 1.4%
|
|
65
|
+
@typescript-eslint/no-unnecessary-type-constraint | 31.189 | 1.3%
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,32 @@
|
|
|
1
1
|
# @utilitywarehouse/hearth-react-native
|
|
2
2
|
|
|
3
|
+
## 0.30.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#1090](https://github.com/utilitywarehouse/hearth/pull/1090) [`1420244`](https://github.com/utilitywarehouse/hearth/commit/1420244fbc23c8a755f9249f8b39cb094a865cea) Thanks [@jordmccord](https://github.com/jordmccord)! - 🌟 [FEATURE]: Add `alignChevron` to `Banner` for horizontal pressable layouts.
|
|
8
|
+
|
|
9
|
+
`Banner` now supports an `alignChevron` prop to control the chevron alignment when `onPress` is used in the horizontal layout. Use `'start'`, `'center'`, or `'end'` to match the chevron position to the content layout.
|
|
10
|
+
|
|
11
|
+
**Components affected**:
|
|
12
|
+
- `Banner`
|
|
13
|
+
|
|
14
|
+
**Developer changes**:
|
|
15
|
+
|
|
16
|
+
No changes are required unless you want to override the default centred chevron alignment.
|
|
17
|
+
|
|
18
|
+
## 0.30.1
|
|
19
|
+
|
|
20
|
+
### Patch Changes
|
|
21
|
+
|
|
22
|
+
- [#1081](https://github.com/utilitywarehouse/hearth/pull/1081) [`5db8538`](https://github.com/utilitywarehouse/hearth/commit/5db8538b69115a23289f0038f681fc8b87a310c4) Thanks [@jordmccord](https://github.com/jordmccord)! - 🐛 [FIX]: Correct `NavModal` safe area handling across sheet and full-screen presentations.
|
|
23
|
+
|
|
24
|
+
`NavModal` now applies safe area insets directly within the component layout, which fixes padding in full-screen presentations and keeps sheet-style presentations aligned with the modal footer behaviour.
|
|
25
|
+
|
|
26
|
+
**Developer changes**:
|
|
27
|
+
|
|
28
|
+
If you need to disable the inset padding, use the `useSafeAreaInsets` prop. The old `safeAreaViewProps` escape hatch is no longer available.
|
|
29
|
+
|
|
3
30
|
## 0.30.0
|
|
4
31
|
|
|
5
32
|
### Minor Changes
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type BannerProps from './Banner.props';
|
|
2
2
|
declare const Banner: {
|
|
3
|
-
({ icon, iconContainerVariant, iconContainerSize, iconContainerColor, illustration, image, heading, description, direction, link, button, onPress, onClose, variant, style, ...props }: BannerProps): import("react/jsx-runtime").JSX.Element;
|
|
3
|
+
({ icon, iconContainerVariant, iconContainerSize, iconContainerColor, illustration, image, heading, description, direction, link, button, onPress, onClose, variant, alignChevron, style, ...props }: BannerProps): import("react/jsx-runtime").JSX.Element;
|
|
4
4
|
displayName: string;
|
|
5
5
|
};
|
|
6
6
|
export default Banner;
|
|
@@ -9,9 +9,14 @@ import { Heading } from '../Heading';
|
|
|
9
9
|
import { IconContainer } from '../IconContainer';
|
|
10
10
|
import { UnstyledIconButton } from '../UnstyledIconButton';
|
|
11
11
|
import BannerContext from './Banner.context';
|
|
12
|
-
const Banner = ({ icon, iconContainerVariant = 'subtle', iconContainerSize = 'md', iconContainerColor = 'pig', illustration, image, heading, description, direction = 'horizontal', link, button, onPress, onClose, variant = 'subtle', style, ...props }) => {
|
|
12
|
+
const Banner = ({ icon, iconContainerVariant = 'subtle', iconContainerSize = 'md', iconContainerColor = 'pig', illustration, image, heading, description, direction = 'horizontal', link, button, onPress, onClose, variant = 'subtle', alignChevron = 'center', style, ...props }) => {
|
|
13
13
|
const hasIllustration = Boolean(illustration);
|
|
14
|
-
styles.useVariants({
|
|
14
|
+
styles.useVariants({
|
|
15
|
+
direction,
|
|
16
|
+
hasIllustration,
|
|
17
|
+
isPressable: Boolean(onPress),
|
|
18
|
+
alignChevron,
|
|
19
|
+
});
|
|
15
20
|
const context = useMemo(() => ({
|
|
16
21
|
direction,
|
|
17
22
|
}), [direction]);
|
|
@@ -187,6 +192,25 @@ const styles = StyleSheet.create(theme => ({
|
|
|
187
192
|
},
|
|
188
193
|
chevron: {
|
|
189
194
|
alignSelf: 'center',
|
|
195
|
+
variants: {
|
|
196
|
+
direction: {
|
|
197
|
+
horizontal: {},
|
|
198
|
+
vertical: {
|
|
199
|
+
display: 'none',
|
|
200
|
+
},
|
|
201
|
+
},
|
|
202
|
+
alignChevron: {
|
|
203
|
+
center: {
|
|
204
|
+
alignSelf: 'center',
|
|
205
|
+
},
|
|
206
|
+
start: {
|
|
207
|
+
alignSelf: 'flex-start',
|
|
208
|
+
},
|
|
209
|
+
end: {
|
|
210
|
+
alignSelf: 'flex-end',
|
|
211
|
+
},
|
|
212
|
+
},
|
|
213
|
+
},
|
|
190
214
|
},
|
|
191
215
|
closeButton: {
|
|
192
216
|
alignSelf: 'flex-start',
|
|
@@ -66,5 +66,10 @@ export interface BannerProps extends Omit<CardProps, 'noPadding' | 'variant' | '
|
|
|
66
66
|
* @default 'subtle'
|
|
67
67
|
*/
|
|
68
68
|
variant?: 'subtle' | 'emphasis';
|
|
69
|
+
/**
|
|
70
|
+
* Chevron alignment for horizontal layout
|
|
71
|
+
* @default 'center'
|
|
72
|
+
*/
|
|
73
|
+
alignChevron?: 'center' | 'start' | 'end';
|
|
69
74
|
}
|
|
70
75
|
export default BannerProps;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import NavModalProps from './NavModal.props';
|
|
2
|
-
declare const NavModal: ({ ref, children, heading, description, showCloseButton, primaryButtonText, secondaryButtonText, onPressPrimaryButton, onPressCloseButton, onPressSecondaryButton, loading, loadingHeading, loadingDescription, image, primaryButtonProps, secondaryButtonProps, closeButtonProps, stickyFooter, background, scrollable, presentation, scrollViewProps,
|
|
2
|
+
declare const NavModal: ({ ref, children, heading, description, showCloseButton, primaryButtonText, secondaryButtonText, onPressPrimaryButton, onPressCloseButton, onPressSecondaryButton, loading, loadingHeading, loadingDescription, image, primaryButtonProps, secondaryButtonProps, closeButtonProps, stickyFooter, background, scrollable, presentation, scrollViewProps, useSafeAreaInsets, ...props }: NavModalProps) => import("react/jsx-runtime").JSX.Element;
|
|
3
3
|
export default NavModal;
|
|
@@ -3,7 +3,6 @@ import { CloseMediumIcon } from '@utilitywarehouse/hearth-react-native-icons';
|
|
|
3
3
|
import { useCallback, useEffect, useImperativeHandle, useMemo } from 'react';
|
|
4
4
|
import { Platform, ScrollView, View } from 'react-native';
|
|
5
5
|
import Animated, { Easing, useAnimatedStyle, useSharedValue, withDelay, withTiming, } from 'react-native-reanimated';
|
|
6
|
-
import { SafeAreaView } from 'react-native-safe-area-context';
|
|
7
6
|
import { StyleSheet } from 'react-native-unistyles';
|
|
8
7
|
import { useTheme } from '../../hooks';
|
|
9
8
|
import { hexWithOpacity } from '../../utils';
|
|
@@ -12,7 +11,7 @@ import { Button } from '../Button';
|
|
|
12
11
|
import { Heading } from '../Heading';
|
|
13
12
|
import { Spinner } from '../Spinner';
|
|
14
13
|
import { UnstyledIconButton } from '../UnstyledIconButton';
|
|
15
|
-
const NavModal = ({ ref, children, heading, description, showCloseButton = true, primaryButtonText, secondaryButtonText, onPressPrimaryButton, onPressCloseButton, onPressSecondaryButton, loading, loadingHeading = 'Loading...', loadingDescription, image, primaryButtonProps, secondaryButtonProps, closeButtonProps, stickyFooter = true, background = 'default', scrollable = true, presentation = 'modal', scrollViewProps,
|
|
14
|
+
const NavModal = ({ ref, children, heading, description, showCloseButton = true, primaryButtonText, secondaryButtonText, onPressPrimaryButton, onPressCloseButton, onPressSecondaryButton, loading, loadingHeading = 'Loading...', loadingDescription, image, primaryButtonProps, secondaryButtonProps, closeButtonProps, stickyFooter = true, background = 'default', scrollable = true, presentation = 'modal', scrollViewProps, useSafeAreaInsets = true, ...props }) => {
|
|
16
15
|
const theme = useTheme();
|
|
17
16
|
const backgroundOpacity = useSharedValue(0);
|
|
18
17
|
const pretendContentTranslateY = useSharedValue(20);
|
|
@@ -66,6 +65,9 @@ const NavModal = ({ ref, children, heading, description, showCloseButton = true,
|
|
|
66
65
|
loading,
|
|
67
66
|
background: isBrandBackground ? 'brand' : 'primary',
|
|
68
67
|
presentation: isFullScreenPresentation ? 'fullScreen' : 'modal',
|
|
68
|
+
useSafeAreaInsets,
|
|
69
|
+
usesSheetPresentation,
|
|
70
|
+
stickyFooter,
|
|
69
71
|
});
|
|
70
72
|
const footer = useMemo(() => (_jsxs(View, { style: styles.footer, children: [onPressPrimaryButton && primaryButtonText ? (_jsx(Button, { onPress: handlePrimaryButtonPress, text: primaryButtonText, inverted: isBrandBackground, ...primaryButtonProps, variant: primaryButtonProps?.variant ?? 'solid', colorScheme: primaryButtonProps?.colorScheme ?? 'highlight' })) : null, onPressSecondaryButton && secondaryButtonText ? (_jsx(Button, { onPress: handleSecondaryButtonPress, text: secondaryButtonText, inverted: isBrandBackground, ...secondaryButtonProps, variant: secondaryButtonProps?.variant ?? 'outline', colorScheme: secondaryButtonProps?.colorScheme ?? 'functional' })) : null] })), [
|
|
71
73
|
handlePrimaryButtonPress,
|
|
@@ -84,19 +86,57 @@ const NavModal = ({ ref, children, heading, description, showCloseButton = true,
|
|
|
84
86
|
}, contentContainerStyle: { paddingHorizontal: 4 }, ...scrollViewProps, children: [children, !stickyFooter && !noButtons ? (_jsx(View, { style: styles.inNavModalFooterContainer, children: footer })) : null] })) : (_jsxs(View, { style: {
|
|
85
87
|
flex: stickyFooter ? 1 : 0,
|
|
86
88
|
}, children: [children, !stickyFooter && !noButtons ? (_jsx(View, { style: styles.inNavModalFooterContainer, children: footer })) : null] })), stickyFooter && !noButtons ? footer : null] })) }));
|
|
87
|
-
|
|
88
|
-
return (_jsxs(SafeAreaView, { style: [
|
|
89
|
-
{
|
|
90
|
-
flex: 1,
|
|
91
|
-
backgroundColor: theme.color.background[isBrandBackground ? 'brand' : 'secondary'],
|
|
92
|
-
},
|
|
93
|
-
safeAreaViewStyle,
|
|
94
|
-
], ...restSafeAreaViewProps, children: [Platform.OS === 'android' && usesSheetPresentation ? (_jsx(Animated.View, { style: [styles.androidContainer, animatedBackgroundStyle], children: _jsx(Animated.View, { style: [styles.pretendContent, animatedPretendContentStyle] }) })) : null, _jsx(Animated.View, { style: [
|
|
89
|
+
return (_jsxs(View, { style: styles.root, children: [Platform.OS === 'android' && usesSheetPresentation ? (_jsx(Animated.View, { style: [styles.androidContainer, animatedBackgroundStyle], children: _jsx(Animated.View, { style: [styles.pretendContent, animatedPretendContentStyle] }) })) : null, _jsx(Animated.View, { style: [
|
|
95
90
|
styles.inNavModalContainer,
|
|
96
91
|
Platform.OS === 'android' && usesSheetPresentation && animatedBackgroundStyle,
|
|
97
92
|
], ...props, children: _jsx(View, { style: styles.inNavModalContent, children: content }) })] }));
|
|
98
93
|
};
|
|
99
94
|
const styles = StyleSheet.create((theme, rt) => ({
|
|
95
|
+
root: {
|
|
96
|
+
flex: 1,
|
|
97
|
+
variants: {
|
|
98
|
+
background: {
|
|
99
|
+
brand: {
|
|
100
|
+
backgroundColor: theme.color.background.brand,
|
|
101
|
+
},
|
|
102
|
+
primary: {
|
|
103
|
+
backgroundColor: theme.color.background.secondary,
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
usesSheetPresentation: {
|
|
107
|
+
true: {},
|
|
108
|
+
false: {},
|
|
109
|
+
},
|
|
110
|
+
useSafeAreaInsets: {
|
|
111
|
+
true: {},
|
|
112
|
+
false: {},
|
|
113
|
+
},
|
|
114
|
+
stickyFooter: {
|
|
115
|
+
true: {},
|
|
116
|
+
false: {},
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
compoundVariants: [
|
|
120
|
+
{
|
|
121
|
+
usesSheetPresentation: false,
|
|
122
|
+
useSafeAreaInsets: true,
|
|
123
|
+
styles: {
|
|
124
|
+
paddingTop: rt.insets.top,
|
|
125
|
+
paddingBottom: Platform.OS === 'ios' ? rt.insets.bottom : 0,
|
|
126
|
+
paddingLeft: rt.insets.left,
|
|
127
|
+
paddingRight: rt.insets.right,
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
usesSheetPresentation: true,
|
|
132
|
+
useSafeAreaInsets: true,
|
|
133
|
+
stickyFooter: true,
|
|
134
|
+
styles: {
|
|
135
|
+
paddingBottom: Platform.OS === 'ios' ? rt.insets.bottom : 0,
|
|
136
|
+
},
|
|
137
|
+
},
|
|
138
|
+
],
|
|
139
|
+
},
|
|
100
140
|
container: {
|
|
101
141
|
flex: 1,
|
|
102
142
|
gap: theme.components.modal.gap,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Ref } from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { ScrollViewProps } from 'react-native';
|
|
3
3
|
import { ModalCommonProps } from '../Modal/Modal.shared.types';
|
|
4
4
|
export interface NavModalRef {
|
|
5
5
|
triggerCloseAnimation?: () => void;
|
|
@@ -9,7 +9,7 @@ interface NavModalProps extends ModalCommonProps {
|
|
|
9
9
|
background?: 'default' | 'brand';
|
|
10
10
|
scrollable?: boolean;
|
|
11
11
|
presentation?: 'fullScreenModal' | 'modal' | 'transparentModal' | 'containedModal' | 'containedTransparentModal';
|
|
12
|
-
|
|
13
|
-
scrollViewProps?: Omit<
|
|
12
|
+
useSafeAreaInsets?: boolean;
|
|
13
|
+
scrollViewProps?: Omit<ScrollViewProps, 'children'>;
|
|
14
14
|
}
|
|
15
15
|
export default NavModalProps;
|
package/docs/changelog.mdx
CHANGED
|
@@ -9,6 +9,73 @@ import { BackToTopButton, NextPrevPage } from './components';
|
|
|
9
9
|
The changelog for the Hearth React Native library. Here you can find all the changes, improvements, and bug fixes for each version.
|
|
10
10
|
|
|
11
11
|
|
|
12
|
+
## 0.30.1
|
|
13
|
+
|
|
14
|
+
### Patch Changes
|
|
15
|
+
|
|
16
|
+
- [#1081](https://github.com/utilitywarehouse/hearth/pull/1081) [`5db8538`](https://github.com/utilitywarehouse/hearth/commit/5db8538b69115a23289f0038f681fc8b87a310c4) Thanks [@jordmccord](https://github.com/jordmccord)! - 🐛 [FIX]: Correct `NavModal` safe area handling across sheet and full-screen presentations.
|
|
17
|
+
|
|
18
|
+
`NavModal` now applies safe area insets directly within the component layout, which fixes padding in full-screen presentations and keeps sheet-style presentations aligned with the modal footer behaviour.
|
|
19
|
+
|
|
20
|
+
**Developer changes**:
|
|
21
|
+
|
|
22
|
+
If you need to disable the inset padding, use the `useSafeAreaInsets` prop. The old `safeAreaViewProps` escape hatch is no longer available.
|
|
23
|
+
|
|
24
|
+
## 0.30.0
|
|
25
|
+
|
|
26
|
+
### Minor Changes
|
|
27
|
+
|
|
28
|
+
- [#1072](https://github.com/utilitywarehouse/hearth/pull/1072) [`55f0095`](https://github.com/utilitywarehouse/hearth/commit/55f009576ba55081de358bccc21691861ddd7c33) Thanks [@jordmccord](https://github.com/jordmccord)! - 🌟 [FEATURE]: Add `loadingDescription` support to `Modal` and `NavModal`
|
|
29
|
+
|
|
30
|
+
`Modal` and `NavModal` now accept a `loadingDescription` prop to render supporting text beneath the spinner while `loading` is true. This makes it easier to give users more context during loading states without building custom loading content.
|
|
31
|
+
|
|
32
|
+
**Components affected**:
|
|
33
|
+
- `Modal`
|
|
34
|
+
- `NavModal`
|
|
35
|
+
|
|
36
|
+
**Developer changes**:
|
|
37
|
+
|
|
38
|
+
No changes are required for existing usage. To show supporting text in a loading state, pass `loadingDescription` alongside `loading` and, if needed, `loadingHeading`.
|
|
39
|
+
|
|
40
|
+
### Patch Changes
|
|
41
|
+
|
|
42
|
+
- [#1070](https://github.com/utilitywarehouse/hearth/pull/1070) [`93c042c`](https://github.com/utilitywarehouse/hearth/commit/93c042c7772ab298e2ea4888a9777e8176453098) Thanks [@jordmccord](https://github.com/jordmccord)! - 🐛 [FIX]: Standardise numeric value typography across list-based components.
|
|
43
|
+
|
|
44
|
+
Numeric values in `DescriptionListItem`, `ExpandableCard`, and `ListItem` now render with semibold `BodyText` instead of `DetailText`, aligning them with the updated content hierarchy used elsewhere in the library.
|
|
45
|
+
|
|
46
|
+
**Components affected**:
|
|
47
|
+
- `DescriptionListItem`
|
|
48
|
+
- `ExpandableCard`
|
|
49
|
+
- `ListItem`
|
|
50
|
+
|
|
51
|
+
**Developer changes**:
|
|
52
|
+
|
|
53
|
+
No changes are required.
|
|
54
|
+
|
|
55
|
+
- [#1073](https://github.com/utilitywarehouse/hearth/pull/1073) [`9759622`](https://github.com/utilitywarehouse/hearth/commit/975962229137dd196e5f72a04037a8f181907818) Thanks [@jordmccord](https://github.com/jordmccord)! - 🐛 [FIX]: Announce `Heading` as a header for assistive technologies.
|
|
56
|
+
|
|
57
|
+
`Heading` now sets `accessibilityRole="header"` automatically so VoiceOver and TalkBack can identify headings as part of the screen structure.
|
|
58
|
+
|
|
59
|
+
**Components affected**:
|
|
60
|
+
- `Heading`
|
|
61
|
+
|
|
62
|
+
**Developer changes**:
|
|
63
|
+
|
|
64
|
+
No changes are required.
|
|
65
|
+
|
|
66
|
+
- [#1074](https://github.com/utilitywarehouse/hearth/pull/1074) [`95fe19e`](https://github.com/utilitywarehouse/hearth/commit/95fe19e6328bf652ff3ac1b2c723e1389fc59936) Thanks [@jordmccord](https://github.com/jordmccord)! - 🐛 [FIX]: Improve accessibility roles for `List`, `ListItem`, and `ListAction`
|
|
67
|
+
|
|
68
|
+
`List` now defaults to `accessibilityRole="list"`, `ListAction` now defaults to `accessibilityRole="button"`, and `ListItem` respects an explicitly provided `accessibilityRole` instead of always forcing button semantics when `onPress` is set.
|
|
69
|
+
|
|
70
|
+
**Components affected**:
|
|
71
|
+
- `List`
|
|
72
|
+
- `ListItem`
|
|
73
|
+
- `ListAction`
|
|
74
|
+
|
|
75
|
+
**Developer changes**:
|
|
76
|
+
|
|
77
|
+
No changes are required unless you want a tappable `ListItem` to be announced as something other than a button. In that case, pass `accessibilityRole` explicitly.
|
|
78
|
+
|
|
12
79
|
## 0.29.2
|
|
13
80
|
|
|
14
81
|
### Patch Changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@utilitywarehouse/hearth-react-native",
|
|
3
|
-
"version": "0.30.
|
|
3
|
+
"version": "0.30.2",
|
|
4
4
|
"description": "Utility Warehouse React Native UI library",
|
|
5
5
|
"main": "build/index.js",
|
|
6
6
|
"types": "build/index.d.ts",
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
"@utilitywarehouse/hearth-fonts": "^0.0.4",
|
|
61
61
|
"@utilitywarehouse/hearth-react-icons": "^0.8.0",
|
|
62
62
|
"@utilitywarehouse/hearth-react-native-icons": "^0.8.0",
|
|
63
|
-
"@utilitywarehouse/hearth-svg-assets": "^0.
|
|
63
|
+
"@utilitywarehouse/hearth-svg-assets": "^0.6.0",
|
|
64
64
|
"@utilitywarehouse/hearth-tokens": "^0.2.4"
|
|
65
65
|
},
|
|
66
66
|
"peerDependencies": {
|
|
@@ -81,6 +81,7 @@ const MyComponent = () => (
|
|
|
81
81
|
| onClose | `() => void` | Shows close button with handler | `-` |
|
|
82
82
|
| variant | `'subtle' \| 'emphasis'` | Card visual style variant | `'subtle'` |
|
|
83
83
|
| colorScheme | `'pig' \| 'energy' \| 'broadband' \| 'mobile' \|` <br />`'insurance' \| 'cashback' \| 'highlight'` | Color scheme for buttons | `'pig'` |
|
|
84
|
+
| alignChevron | `'center' \| 'start' \| 'end'` | Alignment of chevron when `onPress` is used with horizontal layout | `'center'` |
|
|
84
85
|
|
|
85
86
|
The component also accepts all standard Card props except `noPadding`, `spacing`, `gap`, `rowGap`, `columnGap`, `flexDirection`, `flexWrap`, `alignItems`, and `justifyContent`.
|
|
86
87
|
|
|
@@ -87,6 +87,11 @@ export interface BannerProps extends Omit<
|
|
|
87
87
|
* @default 'subtle'
|
|
88
88
|
*/
|
|
89
89
|
variant?: 'subtle' | 'emphasis';
|
|
90
|
+
/**
|
|
91
|
+
* Chevron alignment for horizontal layout
|
|
92
|
+
* @default 'center'
|
|
93
|
+
*/
|
|
94
|
+
alignChevron?: 'center' | 'start' | 'end';
|
|
90
95
|
}
|
|
91
96
|
|
|
92
97
|
export default BannerProps;
|
|
@@ -301,6 +301,22 @@ export const Pressable: Story = {
|
|
|
301
301
|
description="Manage your account preferences."
|
|
302
302
|
onPress={() => console.log('Banner pressed')}
|
|
303
303
|
/>
|
|
304
|
+
<Banner
|
|
305
|
+
direction="vertical"
|
|
306
|
+
image={
|
|
307
|
+
<BannerImage
|
|
308
|
+
light={{
|
|
309
|
+
uri: 'https://images.unsplash.com/photo-1506126613408-eca07ce68773?w=200&q=80',
|
|
310
|
+
}}
|
|
311
|
+
dark={{
|
|
312
|
+
uri: 'https://images.unsplash.com/photo-1506126613408-eca07ce68773?w=200&q=80',
|
|
313
|
+
}}
|
|
314
|
+
/>
|
|
315
|
+
}
|
|
316
|
+
heading="Account Settings"
|
|
317
|
+
description="Manage your account preferences."
|
|
318
|
+
onPress={() => console.log('Banner pressed')}
|
|
319
|
+
/>
|
|
304
320
|
</Flex>
|
|
305
321
|
</View>
|
|
306
322
|
);
|
|
@@ -25,11 +25,17 @@ const Banner = ({
|
|
|
25
25
|
onPress,
|
|
26
26
|
onClose,
|
|
27
27
|
variant = 'subtle',
|
|
28
|
+
alignChevron = 'center',
|
|
28
29
|
style,
|
|
29
30
|
...props
|
|
30
31
|
}: BannerProps) => {
|
|
31
32
|
const hasIllustration = Boolean(illustration);
|
|
32
|
-
styles.useVariants({
|
|
33
|
+
styles.useVariants({
|
|
34
|
+
direction,
|
|
35
|
+
hasIllustration,
|
|
36
|
+
isPressable: Boolean(onPress),
|
|
37
|
+
alignChevron,
|
|
38
|
+
});
|
|
33
39
|
|
|
34
40
|
const context = useMemo(
|
|
35
41
|
() => ({
|
|
@@ -295,6 +301,25 @@ const styles = StyleSheet.create(theme => ({
|
|
|
295
301
|
},
|
|
296
302
|
chevron: {
|
|
297
303
|
alignSelf: 'center',
|
|
304
|
+
variants: {
|
|
305
|
+
direction: {
|
|
306
|
+
horizontal: {},
|
|
307
|
+
vertical: {
|
|
308
|
+
display: 'none',
|
|
309
|
+
},
|
|
310
|
+
},
|
|
311
|
+
alignChevron: {
|
|
312
|
+
center: {
|
|
313
|
+
alignSelf: 'center',
|
|
314
|
+
},
|
|
315
|
+
start: {
|
|
316
|
+
alignSelf: 'flex-start',
|
|
317
|
+
},
|
|
318
|
+
end: {
|
|
319
|
+
alignSelf: 'flex-end',
|
|
320
|
+
},
|
|
321
|
+
},
|
|
322
|
+
},
|
|
298
323
|
},
|
|
299
324
|
closeButton: {
|
|
300
325
|
alignSelf: 'flex-start',
|
|
@@ -135,30 +135,30 @@ const styles = StyleSheet.create({
|
|
|
135
135
|
|
|
136
136
|
`NavModal` supports Hearth's modal content props plus the navigation-specific `background`, `scrollable`, and `presentation` options. Set `presentation` to the same value you pass to React Navigation so `NavModal` can match the route's sheet-style or full-screen layout. It does not take bottom-sheet props such as `snapPoints`, and it does not manage its own dismissal. Your screen or navigator owns closing behavior.
|
|
137
137
|
|
|
138
|
-
| Property | Type | Description
|
|
139
|
-
| ------------------------ | ---------------------------------------------------------------------------------------------------------------- |
|
|
140
|
-
| `heading` | `string` | Heading text shown at the top of the modal when no `image` is provided.
|
|
141
|
-
| `description` | `string` | Supporting text shown below the heading when no `image` is provided.
|
|
142
|
-
| `showCloseButton` | `boolean` | Whether to render the close button in the top-right corner.
|
|
143
|
-
| `primaryButtonText` | `string` | Label for the primary action button.
|
|
144
|
-
| `secondaryButtonText` | `string` | Label for the secondary action button.
|
|
145
|
-
| `onPressPrimaryButton` | `() => void` | Called when the primary action button is pressed.
|
|
146
|
-
| `onPressSecondaryButton` | `() => void` | Called when the secondary action button is pressed.
|
|
147
|
-
| `onPressCloseButton` | `() => void` | Called when the close button is pressed.
|
|
148
|
-
| `primaryButtonProps` | `Omit<ButtonWithoutChildrenProps, 'children'>` | Extra props forwarded to the primary button.
|
|
149
|
-
| `secondaryButtonProps` | `Omit<ButtonWithoutChildrenProps, 'children'>` | Extra props forwarded to the secondary button.
|
|
150
|
-
| `closeButtonProps` | `Omit<UnstyledIconButtonProps, 'children'>` | Extra props forwarded to the close button.
|
|
151
|
-
| `loading` | `boolean` | Replaces the content with a loading state and spinner.
|
|
152
|
-
| `loadingHeading` | `string` | Heading text shown while `loading` is true.
|
|
153
|
-
| `loadingDescription` | `string` | Supporting text shown below the heading while `loading` is true.
|
|
154
|
-
| `image` | `ReactNode` | Optional image or illustration shown above the text content.
|
|
155
|
-
| `children` | `ReactNode` | Content rendered inside the modal body.
|
|
156
|
-
| `stickyFooter` | `boolean` | Keeps action buttons pinned to the bottom instead of flowing with the content.
|
|
157
|
-
| `background` | `'default' /\| 'brand'` | Switches between the default surface background and the brand background treatment.
|
|
158
|
-
| `scrollable` | `boolean` | Wraps the content area in a `ScrollView`. Set this to `false` for custom layouts that should not scroll.
|
|
159
|
-
| `presentation` | `'modal' \| 'fullScreenModal' \| 'transparentModal' `<br />` \| 'containedModal' \| 'containedTransparentModal'` | Matches the React Navigation screen presentation. `fullScreenModal` uses the full-screen layout; the other values use the sheet-style layout.
|
|
160
|
-
| `
|
|
161
|
-
| `scrollViewProps` | `ScrollViewProps` | Extra props forwarded to the `ScrollView` wrapping the modal content when `scrollable` is true.
|
|
138
|
+
| Property | Type | Description | Default |
|
|
139
|
+
| ------------------------ | ---------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------- |
|
|
140
|
+
| `heading` | `string` | Heading text shown at the top of the modal when no `image` is provided. | - |
|
|
141
|
+
| `description` | `string` | Supporting text shown below the heading when no `image` is provided. | - |
|
|
142
|
+
| `showCloseButton` | `boolean` | Whether to render the close button in the top-right corner. | `true` |
|
|
143
|
+
| `primaryButtonText` | `string` | Label for the primary action button. | - |
|
|
144
|
+
| `secondaryButtonText` | `string` | Label for the secondary action button. | - |
|
|
145
|
+
| `onPressPrimaryButton` | `() => void` | Called when the primary action button is pressed. | - |
|
|
146
|
+
| `onPressSecondaryButton` | `() => void` | Called when the secondary action button is pressed. | - |
|
|
147
|
+
| `onPressCloseButton` | `() => void` | Called when the close button is pressed. | - |
|
|
148
|
+
| `primaryButtonProps` | `Omit<ButtonWithoutChildrenProps, 'children'>` | Extra props forwarded to the primary button. | - |
|
|
149
|
+
| `secondaryButtonProps` | `Omit<ButtonWithoutChildrenProps, 'children'>` | Extra props forwarded to the secondary button. | - |
|
|
150
|
+
| `closeButtonProps` | `Omit<UnstyledIconButtonProps, 'children'>` | Extra props forwarded to the close button. | - |
|
|
151
|
+
| `loading` | `boolean` | Replaces the content with a loading state and spinner. | `false` |
|
|
152
|
+
| `loadingHeading` | `string` | Heading text shown while `loading` is true. | `'Loading...'` |
|
|
153
|
+
| `loadingDescription` | `string` | Supporting text shown below the heading while `loading` is true. | - |
|
|
154
|
+
| `image` | `ReactNode` | Optional image or illustration shown above the text content. | - |
|
|
155
|
+
| `children` | `ReactNode` | Content rendered inside the modal body. | - |
|
|
156
|
+
| `stickyFooter` | `boolean` | Keeps action buttons pinned to the bottom instead of flowing with the content. | `true` |
|
|
157
|
+
| `background` | `'default' /\| 'brand'` | Switches between the default surface background and the brand background treatment. | `'default'` |
|
|
158
|
+
| `scrollable` | `boolean` | Wraps the content area in a `ScrollView`. Set this to `false` for custom layouts that should not scroll. | `true` |
|
|
159
|
+
| `presentation` | `'modal' \| 'fullScreenModal' \| 'transparentModal' `<br />` \| 'containedModal' \| 'containedTransparentModal'` | Matches the React Navigation screen presentation. `fullScreenModal` uses the full-screen layout; the other values use the sheet-style layout. | `'modal'` |
|
|
160
|
+
| `useSafeAreaInsets` | `boolean` | Whether to apply safe area insets as padding within the component. This is enabled by default to fix full-screen presentation padding but can be disabled if you want to manage insets yourself. | `true` |
|
|
161
|
+
| `scrollViewProps` | `ScrollViewProps` | Extra props forwarded to the `ScrollView` wrapping the modal content when `scrollable` is true. | - |
|
|
162
162
|
|
|
163
163
|
## Accessibility
|
|
164
164
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Ref } from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { ScrollViewProps } from 'react-native';
|
|
3
3
|
import { ModalCommonProps } from '../Modal/Modal.shared.types';
|
|
4
4
|
|
|
5
5
|
export interface NavModalRef {
|
|
@@ -16,8 +16,8 @@ interface NavModalProps extends ModalCommonProps {
|
|
|
16
16
|
| 'transparentModal'
|
|
17
17
|
| 'containedModal'
|
|
18
18
|
| 'containedTransparentModal';
|
|
19
|
-
|
|
20
|
-
scrollViewProps?: Omit<
|
|
19
|
+
useSafeAreaInsets?: boolean;
|
|
20
|
+
scrollViewProps?: Omit<ScrollViewProps, 'children'>;
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
export default NavModalProps;
|
|
@@ -8,7 +8,6 @@ import Animated, {
|
|
|
8
8
|
withDelay,
|
|
9
9
|
withTiming,
|
|
10
10
|
} from 'react-native-reanimated';
|
|
11
|
-
import { SafeAreaView } from 'react-native-safe-area-context';
|
|
12
11
|
import { StyleSheet } from 'react-native-unistyles';
|
|
13
12
|
import { useTheme } from '../../hooks';
|
|
14
13
|
import { hexWithOpacity } from '../../utils';
|
|
@@ -42,7 +41,7 @@ const NavModal = ({
|
|
|
42
41
|
scrollable = true,
|
|
43
42
|
presentation = 'modal',
|
|
44
43
|
scrollViewProps,
|
|
45
|
-
|
|
44
|
+
useSafeAreaInsets = true,
|
|
46
45
|
...props
|
|
47
46
|
}: NavModalProps) => {
|
|
48
47
|
const theme = useTheme();
|
|
@@ -117,6 +116,9 @@ const NavModal = ({
|
|
|
117
116
|
loading,
|
|
118
117
|
background: isBrandBackground ? 'brand' : 'primary',
|
|
119
118
|
presentation: isFullScreenPresentation ? 'fullScreen' : 'modal',
|
|
119
|
+
useSafeAreaInsets,
|
|
120
|
+
usesSheetPresentation,
|
|
121
|
+
stickyFooter,
|
|
120
122
|
});
|
|
121
123
|
|
|
122
124
|
const footer = useMemo(
|
|
@@ -258,19 +260,8 @@ const NavModal = ({
|
|
|
258
260
|
</>
|
|
259
261
|
);
|
|
260
262
|
|
|
261
|
-
const { style: safeAreaViewStyle, ...restSafeAreaViewProps } = safeAreaViewProps ?? {};
|
|
262
|
-
|
|
263
263
|
return (
|
|
264
|
-
<
|
|
265
|
-
style={[
|
|
266
|
-
{
|
|
267
|
-
flex: 1,
|
|
268
|
-
backgroundColor: theme.color.background[isBrandBackground ? 'brand' : 'secondary'],
|
|
269
|
-
},
|
|
270
|
-
safeAreaViewStyle,
|
|
271
|
-
]}
|
|
272
|
-
{...restSafeAreaViewProps}
|
|
273
|
-
>
|
|
264
|
+
<View style={styles.root}>
|
|
274
265
|
{Platform.OS === 'android' && usesSheetPresentation ? (
|
|
275
266
|
<Animated.View style={[styles.androidContainer, animatedBackgroundStyle]}>
|
|
276
267
|
<Animated.View style={[styles.pretendContent, animatedPretendContentStyle]} />
|
|
@@ -285,11 +276,56 @@ const NavModal = ({
|
|
|
285
276
|
>
|
|
286
277
|
<View style={styles.inNavModalContent}>{content}</View>
|
|
287
278
|
</Animated.View>
|
|
288
|
-
</
|
|
279
|
+
</View>
|
|
289
280
|
);
|
|
290
281
|
};
|
|
291
282
|
|
|
292
283
|
const styles = StyleSheet.create((theme, rt) => ({
|
|
284
|
+
root: {
|
|
285
|
+
flex: 1,
|
|
286
|
+
variants: {
|
|
287
|
+
background: {
|
|
288
|
+
brand: {
|
|
289
|
+
backgroundColor: theme.color.background.brand,
|
|
290
|
+
},
|
|
291
|
+
primary: {
|
|
292
|
+
backgroundColor: theme.color.background.secondary,
|
|
293
|
+
},
|
|
294
|
+
},
|
|
295
|
+
usesSheetPresentation: {
|
|
296
|
+
true: {},
|
|
297
|
+
false: {},
|
|
298
|
+
},
|
|
299
|
+
useSafeAreaInsets: {
|
|
300
|
+
true: {},
|
|
301
|
+
false: {},
|
|
302
|
+
},
|
|
303
|
+
stickyFooter: {
|
|
304
|
+
true: {},
|
|
305
|
+
false: {},
|
|
306
|
+
},
|
|
307
|
+
},
|
|
308
|
+
compoundVariants: [
|
|
309
|
+
{
|
|
310
|
+
usesSheetPresentation: false,
|
|
311
|
+
useSafeAreaInsets: true,
|
|
312
|
+
styles: {
|
|
313
|
+
paddingTop: rt.insets.top,
|
|
314
|
+
paddingBottom: Platform.OS === 'ios' ? rt.insets.bottom : 0,
|
|
315
|
+
paddingLeft: rt.insets.left,
|
|
316
|
+
paddingRight: rt.insets.right,
|
|
317
|
+
},
|
|
318
|
+
},
|
|
319
|
+
{
|
|
320
|
+
usesSheetPresentation: true,
|
|
321
|
+
useSafeAreaInsets: true,
|
|
322
|
+
stickyFooter: true,
|
|
323
|
+
styles: {
|
|
324
|
+
paddingBottom: Platform.OS === 'ios' ? rt.insets.bottom : 0,
|
|
325
|
+
},
|
|
326
|
+
},
|
|
327
|
+
],
|
|
328
|
+
},
|
|
293
329
|
container: {
|
|
294
330
|
flex: 1,
|
|
295
331
|
gap: theme.components.modal.gap,
|