@utilitywarehouse/hearth-react-native 0.28.5 → 0.29.0

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.
Files changed (47) hide show
  1. package/.storybook/preview.tsx +7 -4
  2. package/.turbo/turbo-build.log +1 -1
  3. package/.turbo/turbo-lint.log +12 -15
  4. package/CHANGELOG.md +50 -0
  5. package/build/components/Combobox/Combobox.js +1 -1
  6. package/build/components/Modal/Modal.d.ts +1 -1
  7. package/build/components/Modal/Modal.js +6 -95
  8. package/build/components/Modal/Modal.props.d.ts +2 -31
  9. package/build/components/Modal/Modal.shared.types.d.ts +22 -0
  10. package/build/components/Modal/Modal.web.d.ts +1 -1
  11. package/build/components/Modal/Modal.web.js +6 -71
  12. package/build/components/NavModal/NavModal.d.ts +3 -0
  13. package/build/components/NavModal/NavModal.js +190 -0
  14. package/build/components/NavModal/NavModal.props.d.ts +15 -0
  15. package/build/components/NavModal/NavModal.props.js +1 -0
  16. package/build/components/NavModal/index.d.ts +2 -0
  17. package/build/components/NavModal/index.js +1 -0
  18. package/build/components/Select/Select.js +1 -1
  19. package/build/components/index.d.ts +2 -1
  20. package/build/components/index.js +2 -1
  21. package/docs/changelog.mdx +34 -0
  22. package/docs/components/AllComponents.web.tsx +709 -689
  23. package/package.json +7 -5
  24. package/src/components/Combobox/Combobox.tsx +1 -1
  25. package/src/components/Modal/Modal.docs.mdx +5 -122
  26. package/src/components/Modal/Modal.props.ts +2 -34
  27. package/src/components/Modal/Modal.shared.types.ts +23 -0
  28. package/src/components/Modal/Modal.stories.tsx +0 -1
  29. package/src/components/Modal/Modal.tsx +11 -174
  30. package/src/components/Modal/Modal.web.tsx +29 -127
  31. package/src/components/NavModal/NavModal.docs.mdx +178 -0
  32. package/src/components/NavModal/NavModal.figma.tsx +13 -0
  33. package/src/components/NavModal/NavModal.props.ts +23 -0
  34. package/src/components/NavModal/NavModal.stories.tsx +131 -0
  35. package/src/components/NavModal/NavModal.tsx +375 -0
  36. package/src/components/NavModal/index.ts +2 -0
  37. package/src/components/Select/Select.tsx +1 -1
  38. package/src/components/index.ts +3 -1
  39. package/build/components/SafeAreaView/SafeAreaView.d.ts +0 -5
  40. package/build/components/SafeAreaView/SafeAreaView.js +0 -117
  41. package/build/components/SafeAreaView/SafeAreaView.props.d.ts +0 -17
  42. package/build/components/SafeAreaView/index.d.ts +0 -2
  43. package/build/components/SafeAreaView/index.js +0 -1
  44. package/src/components/SafeAreaView/SafeAreaView.props.ts +0 -20
  45. package/src/components/SafeAreaView/SafeAreaView.tsx +0 -173
  46. package/src/components/SafeAreaView/index.ts +0 -2
  47. /package/build/components/{SafeAreaView/SafeAreaView.props.js → Modal/Modal.shared.types.js} +0 -0
@@ -0,0 +1,190 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { CloseMediumIcon } from '@utilitywarehouse/hearth-react-native-icons';
3
+ import { useCallback, useEffect, useImperativeHandle, useMemo } from 'react';
4
+ import { Platform, ScrollView, View } from 'react-native';
5
+ import Animated, { Easing, useAnimatedStyle, useSharedValue, withDelay, withTiming, } from 'react-native-reanimated';
6
+ import { SafeAreaView } from 'react-native-safe-area-context';
7
+ import { StyleSheet } from 'react-native-unistyles';
8
+ import { useTheme } from '../../hooks';
9
+ import { hexWithOpacity } from '../../utils';
10
+ import { BodyText } from '../BodyText';
11
+ import { Button } from '../Button';
12
+ import { Heading } from '../Heading';
13
+ import { Spinner } from '../Spinner';
14
+ import { UnstyledIconButton } from '../UnstyledIconButton';
15
+ const NavModal = ({ ref, children, heading, description, showCloseButton = true, primaryButtonText, secondaryButtonText, onPressPrimaryButton, onPressCloseButton, onPressSecondaryButton, loading, loadingHeading = 'Loading...', image, primaryButtonProps, secondaryButtonProps, closeButtonProps, stickyFooter = true, background = 'default', scrollable = true, presentation = 'modal', scrollViewProps, safeAreaViewProps, ...props }) => {
16
+ const theme = useTheme();
17
+ const backgroundOpacity = useSharedValue(0);
18
+ const pretendContentTranslateY = useSharedValue(20);
19
+ const isBrandBackground = background === 'brand';
20
+ const isFullScreenPresentation = presentation === 'fullScreenModal';
21
+ const usesSheetPresentation = !isFullScreenPresentation;
22
+ const triggerCloseAnimation = useCallback(() => {
23
+ if (Platform.OS === 'android') {
24
+ pretendContentTranslateY.value = withTiming(20, {
25
+ duration: 50,
26
+ easing: Easing.in(Easing.quad),
27
+ });
28
+ backgroundOpacity.value = withTiming(0, {
29
+ duration: 100,
30
+ easing: Easing.in(Easing.quad),
31
+ });
32
+ }
33
+ }, [backgroundOpacity, pretendContentTranslateY]);
34
+ useImperativeHandle(ref, () => ({
35
+ triggerCloseAnimation,
36
+ }));
37
+ useEffect(() => {
38
+ if (Platform.OS === 'android') {
39
+ backgroundOpacity.value = withDelay(300, withTiming(1, {
40
+ duration: 200,
41
+ easing: Easing.out(Easing.quad),
42
+ }));
43
+ pretendContentTranslateY.value = withDelay(500, withTiming(0, {
44
+ duration: 300,
45
+ easing: Easing.out(Easing.quad),
46
+ }));
47
+ }
48
+ }, [backgroundOpacity, pretendContentTranslateY]);
49
+ const animatedBackgroundStyle = useAnimatedStyle(() => ({
50
+ backgroundColor: hexWithOpacity(theme.components.overlay.backgroundColor, backgroundOpacity.value * (theme.components.overlay.opacity / 100)),
51
+ }));
52
+ const animatedPretendContentStyle = useAnimatedStyle(() => ({
53
+ transform: [{ translateY: pretendContentTranslateY.value }],
54
+ }));
55
+ const handleCloseButtonPress = useCallback(() => {
56
+ onPressCloseButton?.();
57
+ }, [onPressCloseButton]);
58
+ const handlePrimaryButtonPress = useCallback(() => {
59
+ onPressPrimaryButton?.();
60
+ }, [onPressPrimaryButton]);
61
+ const handleSecondaryButtonPress = useCallback(() => {
62
+ onPressSecondaryButton?.();
63
+ }, [onPressSecondaryButton]);
64
+ const noButtons = !onPressPrimaryButton && !onPressSecondaryButton;
65
+ styles.useVariants({
66
+ loading,
67
+ background: isBrandBackground ? 'brand' : 'primary',
68
+ presentation: isFullScreenPresentation ? 'fullScreen' : 'modal',
69
+ });
70
+ 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
+ handlePrimaryButtonPress,
72
+ handleSecondaryButtonPress,
73
+ isBrandBackground,
74
+ onPressPrimaryButton,
75
+ onPressSecondaryButton,
76
+ primaryButtonProps,
77
+ primaryButtonText,
78
+ secondaryButtonProps,
79
+ secondaryButtonText,
80
+ ]);
81
+ const content = (_jsx(_Fragment, { children: loading ? (_jsxs(View, { style: styles.loadingContainer, accessible: Platform.OS === 'android' ? true : undefined, accessibilityLabel: Platform.OS === 'android' ? 'Loading' : undefined, screenReaderFocusable: true, children: [_jsx(Spinner, { size: "lg", color: isBrandBackground ? theme.color.icon.inverted : undefined }), _jsx(Heading, { size: "lg", textAlign: "center", inverted: isBrandBackground, children: loadingHeading })] })) : (_jsxs(View, { style: styles.container, accessible: Platform.OS === 'android' ? true : undefined, accessibilityLabel: Platform.OS === 'android' ? 'Modal content' : undefined, screenReaderFocusable: true, children: [_jsxs(View, { style: styles.header, children: [_jsxs(View, { style: styles.headerTextContent, children: [heading && !image ? (_jsx(Heading, { size: "lg", accessible: true, inverted: isBrandBackground, children: heading })) : null, description && !image ? (_jsx(BodyText, { accessible: true, inverted: isBrandBackground, children: description })) : null] }), showCloseButton ? (_jsx(UnstyledIconButton, { icon: CloseMediumIcon, onPress: handleCloseButtonPress, accessibilityLabel: "Close modal", inverted: isBrandBackground, ...closeButtonProps })) : null] }), image ? (_jsxs(View, { style: styles.imageContainer, children: [image, _jsxs(View, { style: styles.textContent, children: [heading ? (_jsx(Heading, { size: "lg", textAlign: "center", accessible: true, inverted: isBrandBackground, children: heading })) : null, description ? (_jsx(BodyText, { textAlign: "center", accessible: true, inverted: isBrandBackground, children: description })) : null] })] })) : null, scrollable ? (_jsxs(ScrollView, { style: {
82
+ flex: stickyFooter ? 1 : 0,
83
+ marginHorizontal: -4,
84
+ }, contentContainerStyle: { paddingHorizontal: 4 }, ...scrollViewProps, children: [children, !stickyFooter && !noButtons ? (_jsx(View, { style: styles.inNavModalFooterContainer, children: footer })) : null] })) : (_jsxs(View, { style: {
85
+ flex: stickyFooter ? 1 : 0,
86
+ }, children: [children, !stickyFooter && !noButtons ? (_jsx(View, { style: styles.inNavModalFooterContainer, children: footer })) : null] })), stickyFooter && !noButtons ? footer : null] })) }));
87
+ const { style: safeAreaViewStyle, ...restSafeAreaViewProps } = safeAreaViewProps ?? {};
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: [
95
+ styles.inNavModalContainer,
96
+ Platform.OS === 'android' && usesSheetPresentation && animatedBackgroundStyle,
97
+ ], ...props, children: _jsx(View, { style: styles.inNavModalContent, children: content }) })] }));
98
+ };
99
+ const styles = StyleSheet.create((theme, rt) => ({
100
+ container: {
101
+ flex: 1,
102
+ gap: theme.components.modal.gap,
103
+ variants: {
104
+ loading: {
105
+ true: {
106
+ paddingTop: 0,
107
+ },
108
+ },
109
+ },
110
+ },
111
+ header: {
112
+ flexDirection: 'row',
113
+ gap: theme.components.modal.gap,
114
+ },
115
+ headerTextContent: {
116
+ flex: 1,
117
+ gap: theme.components.modal.content.gap,
118
+ },
119
+ imageContainer: {
120
+ alignItems: 'center',
121
+ flex: 1,
122
+ },
123
+ textContent: {
124
+ gap: theme.components.modal.content.gap,
125
+ },
126
+ loadingContainer: {
127
+ borderTopLeftRadius: theme.components.modal.borderRadius,
128
+ borderTopRightRadius: theme.components.modal.borderRadius,
129
+ flex: 1,
130
+ alignItems: 'center',
131
+ justifyContent: 'center',
132
+ minHeight: 140,
133
+ gap: theme.components.modal.content.gap,
134
+ },
135
+ footer: {
136
+ gap: theme.components.modal.action.gap,
137
+ },
138
+ inNavModalContainer: {
139
+ flex: 1,
140
+ variants: {
141
+ presentation: {
142
+ modal: {
143
+ ...(Platform.OS === 'ios'
144
+ ? { backgroundColor: theme.components.overlay.backgroundColor }
145
+ : {}),
146
+ },
147
+ fullScreen: {},
148
+ },
149
+ },
150
+ },
151
+ inNavModalContent: {
152
+ flex: 1,
153
+ variants: {
154
+ background: {
155
+ primary: {},
156
+ brand: {
157
+ backgroundColor: theme.color.background.brand,
158
+ },
159
+ },
160
+ presentation: {
161
+ modal: {
162
+ borderTopLeftRadius: theme.components.modal.borderRadius,
163
+ borderTopRightRadius: theme.components.modal.borderRadius,
164
+ backgroundColor: theme.color.surface.neutral.strong,
165
+ padding: theme.components.bottomSheet.padding,
166
+ },
167
+ fullScreen: {
168
+ backgroundColor: theme.color.surface.neutral.strong,
169
+ padding: theme.components.bottomSheet.padding,
170
+ },
171
+ },
172
+ },
173
+ },
174
+ inNavModalFooterContainer: {
175
+ paddingTop: theme.components.modal.padding,
176
+ },
177
+ androidContainer: {
178
+ height: rt.insets.top + 18,
179
+ paddingLeft: theme.components.modal.padding,
180
+ paddingRight: theme.components.modal.padding,
181
+ justifyContent: 'flex-end',
182
+ },
183
+ pretendContent: {
184
+ borderTopLeftRadius: theme.components.modal.borderRadius,
185
+ borderTopRightRadius: theme.components.modal.borderRadius,
186
+ height: 12,
187
+ backgroundColor: theme.components.parts.modalStack.backgroundColorCardTop,
188
+ },
189
+ }));
190
+ export default NavModal;
@@ -0,0 +1,15 @@
1
+ import { Ref } from 'react';
2
+ import { SafeAreaViewProps } from 'react-native-safe-area-context';
3
+ import { ModalCommonProps } from '../Modal/Modal.shared.types';
4
+ export interface NavModalRef {
5
+ triggerCloseAnimation?: () => void;
6
+ }
7
+ interface NavModalProps extends ModalCommonProps {
8
+ ref?: Ref<NavModalRef>;
9
+ background?: 'default' | 'brand';
10
+ scrollable?: boolean;
11
+ presentation?: 'fullScreenModal' | 'modal' | 'transparentModal' | 'containedModal' | 'containedTransparentModal';
12
+ safeAreaViewProps?: Omit<SafeAreaViewProps, 'children'>;
13
+ scrollViewProps?: Omit<SafeAreaViewProps, 'children'>;
14
+ }
15
+ export default NavModalProps;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,2 @@
1
+ export { default as NavModal } from './NavModal';
2
+ export type { default as NavModalProps, NavModalRef } from './NavModal.props';
@@ -0,0 +1 @@
1
+ export { default as NavModal } from './NavModal';
@@ -2,6 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { ExpandSmallIcon } from '@utilitywarehouse/hearth-react-native-icons';
3
3
  import React, { useCallback, useRef, useState } from 'react';
4
4
  import { Pressable, View } from 'react-native';
5
+ import { SafeAreaView } from 'react-native-safe-area-context';
5
6
  import { StyleSheet } from 'react-native-unistyles';
6
7
  import { BodyText } from '../BodyText';
7
8
  import { BottomSheetFlatList, BottomSheetModal, BottomSheetScrollView, BottomSheetView, } from '../BottomSheet';
@@ -11,7 +12,6 @@ import { Icon } from '../Icon';
11
12
  import { Input } from '../Input';
12
13
  import { SelectContext } from './Select.context';
13
14
  import SelectOption from './SelectOption';
14
- import { SafeAreaView } from '../SafeAreaView';
15
15
  const Select = ({ options = [], value, onValueChange, label, labelVariant = 'body', placeholder = 'Select an option', disabled = false, leadingIcon: LeadingIcon, validationStatus = 'initial', helperText, helperIcon, invalidText, validText, required = true, children, bottomSheetProps, menuHeading, readonly = false, emptyText = 'No options available', listProps, searchable = false, searchPlaceholder = 'Search', testID, ...rest }) => {
16
16
  const formFieldContext = useFormFieldContext();
17
17
  const validationStatusFromContext = formFieldContext?.validationStatus ?? validationStatus;
@@ -40,13 +40,13 @@ export * from './Link';
40
40
  export * from './List';
41
41
  export * from './Menu';
42
42
  export * from './Modal';
43
+ export * from './NavModal';
43
44
  export * from './Pagination';
44
45
  export * from './PillGroup';
45
46
  export * from './ProgressBar';
46
47
  export * from './ProgressStepper';
47
48
  export * from './Radio';
48
49
  export * from './RadioCard';
49
- export * from './SafeAreaView';
50
50
  export * from './SectionHeader';
51
51
  export * from './SegmentedControl';
52
52
  export * from './Select';
@@ -65,4 +65,5 @@ export * from './ToggleButtonCard';
65
65
  export * from './VerificationInput';
66
66
  export { FlatList, Image, KeyboardAvoidingView, ScrollView, SectionList, View } from 'react-native';
67
67
  export { Pressable } from 'react-native';
68
+ export { SafeAreaView } from 'react-native-safe-area-context';
68
69
  export { createIcon } from '@gluestack-ui/icon';
@@ -41,13 +41,13 @@ export * from './Link';
41
41
  export * from './List';
42
42
  export * from './Menu';
43
43
  export * from './Modal';
44
+ export * from './NavModal';
44
45
  export * from './Pagination';
45
46
  export * from './PillGroup';
46
47
  export * from './ProgressBar';
47
48
  export * from './ProgressStepper';
48
49
  export * from './Radio';
49
50
  export * from './RadioCard';
50
- export * from './SafeAreaView';
51
51
  export * from './SectionHeader';
52
52
  export * from './SegmentedControl';
53
53
  export * from './Select';
@@ -66,4 +66,5 @@ export * from './ToggleButtonCard';
66
66
  export * from './VerificationInput';
67
67
  export { FlatList, Image, KeyboardAvoidingView, ScrollView, SectionList, View } from 'react-native';
68
68
  export { Pressable } from 'react-native';
69
+ export { SafeAreaView } from 'react-native-safe-area-context';
69
70
  export { createIcon } from '@gluestack-ui/icon';
@@ -9,6 +9,40 @@ 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.28.6
13
+
14
+ ### Patch Changes
15
+
16
+ - [#1050](https://github.com/utilitywarehouse/hearth/pull/1050) [`13d2cca`](https://github.com/utilitywarehouse/hearth/commit/13d2ccab3abda60a35202847e3895017496c4dcf) Thanks [@jordmccord](https://github.com/jordmccord)! - 🐛 [FIX]: Expand react peer dependency to allow any React 19.x version for compatibility with all React 19 releases.
17
+
18
+ ## 0.28.5
19
+
20
+ ### Patch Changes
21
+
22
+ - [#1045](https://github.com/utilitywarehouse/hearth/pull/1045) [`3778061`](https://github.com/utilitywarehouse/hearth/commit/37780613890221368edb74c0ce83b8bf3d03e5b3) Thanks [@jordmccord](https://github.com/jordmccord)! - 🐛 [FIX]: The `BannerIllustration` now stays centered in vertical banners and no longer inherits image border styling or horizontal stretching.
23
+
24
+ ## 0.28.4
25
+
26
+ ### Patch Changes
27
+
28
+ - [#1034](https://github.com/utilitywarehouse/hearth/pull/1034) [`76598eb`](https://github.com/utilitywarehouse/hearth/commit/76598eb0374c79f9e6c2c23c421f2b9602fbb113) Thanks [@jordmccord](https://github.com/jordmccord)! - 🐛 [FIX]: The `CheckboxTile` spacing now uses the tile gap token instead of the base checkbox gap token.
29
+
30
+ - [#1034](https://github.com/utilitywarehouse/hearth/pull/1034) [`76598eb`](https://github.com/utilitywarehouse/hearth/commit/76598eb0374c79f9e6c2c23c421f2b9602fbb113) Thanks [@jordmccord](https://github.com/jordmccord)! - 🐛 [FIX]: The `Combobox` trigger outline so it is only shown when the control is focused.
31
+
32
+ - [#1034](https://github.com/utilitywarehouse/hearth/pull/1034) [`76598eb`](https://github.com/utilitywarehouse/hearth/commit/76598eb0374c79f9e6c2c23c421f2b9602fbb113) Thanks [@jordmccord](https://github.com/jordmccord)! - 🐛 [FIX]: The `RadioTile` spacing now uses the tile gap token instead of the base radio gap token.
33
+
34
+ - [#1036](https://github.com/utilitywarehouse/hearth/pull/1036) [`b7636e6`](https://github.com/utilitywarehouse/hearth/commit/b7636e6185879264e8d929c3be44fd0d1a354c22) Thanks [@jordmccord](https://github.com/jordmccord)! - 🐛 [FIX]: The `CurrencyInput` font size.
35
+
36
+ - [#1039](https://github.com/utilitywarehouse/hearth/pull/1039) [`3a895bc`](https://github.com/utilitywarehouse/hearth/commit/3a895bcb8dcceb7d55a454ec63de9256d2d8322f) Thanks [@jordmccord](https://github.com/jordmccord)! - 💅 [ENHANCEMENT]: Align all `Radio` and `Checkbox` default and tile gap sizes.
37
+
38
+ - [#1035](https://github.com/utilitywarehouse/hearth/pull/1035) [`01633a7`](https://github.com/utilitywarehouse/hearth/commit/01633a73153563d9b2286f42b764ad771e48ff82) Thanks [@jordmccord](https://github.com/jordmccord)! - 🐛 [FIX]: The `Pill` component no longer applies extra vertical padding and fixes vertical alignment.
39
+
40
+ ## 0.28.3
41
+
42
+ ### Patch Changes
43
+
44
+ - [#1028](https://github.com/utilitywarehouse/hearth/pull/1028) [`dccffe1`](https://github.com/utilitywarehouse/hearth/commit/dccffe16342b22e58078dfc0aadfe9a482bfcc74) Thanks [@jordmccord](https://github.com/jordmccord)! - 🐛 [FIX]: The `Combobox` trigger outline so it is only shown when the control is focused.
45
+
12
46
  ## 0.28.2
13
47
 
14
48
  ### Patch Changes