@utilitywarehouse/hearth-react-native 0.29.1 → 0.30.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.
- package/.turbo/turbo-build.log +1 -1
- package/.turbo/turbo-lint.log +13 -13
- package/CHANGELOG.md +82 -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/DescriptionList/DescriptionListItem.js +1 -2
- package/build/components/ExpandableCard/ExpandableCardTriggerRoot.js +2 -2
- package/build/components/Heading/Heading.js +1 -1
- package/build/components/List/List.js +2 -2
- package/build/components/List/ListAction/ListAction.js +1 -1
- package/build/components/List/ListItem/ListItemRoot.js +2 -2
- package/build/components/Modal/Modal.d.ts +1 -1
- package/build/components/Modal/Modal.js +56 -10
- package/build/components/Modal/Modal.shared.types.d.ts +1 -0
- package/build/components/NavModal/NavModal.d.ts +1 -1
- package/build/components/NavModal/NavModal.js +2 -2
- package/build/components/Select/Select.js +3 -1
- package/docs/changelog.mdx +86 -0
- package/package.json +3 -3
- 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/DescriptionList/DescriptionListItem.tsx +1 -2
- package/src/components/ExpandableCard/ExpandableCardTriggerRoot.tsx +4 -4
- package/src/components/Heading/Heading.docs.mdx +12 -3
- package/src/components/Heading/Heading.tsx +1 -0
- package/src/components/List/List.docs.mdx +2 -2
- package/src/components/List/List.stories.tsx +6 -5
- package/src/components/List/List.tsx +14 -2
- package/src/components/List/ListAction/ListAction.tsx +1 -0
- package/src/components/List/ListItem/ListItemRoot.tsx +3 -3
- package/src/components/Modal/Modal.docs.mdx +36 -21
- package/src/components/Modal/Modal.shared.types.ts +1 -0
- package/src/components/Modal/Modal.tsx +60 -9
- package/src/components/NavModal/NavModal.docs.mdx +1 -0
- package/src/components/NavModal/NavModal.tsx +10 -1
- package/src/components/Select/Select.tsx +3 -1
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
} from '@utilitywarehouse/hearth-react-native-icons';
|
|
5
5
|
import { Pressable, ViewStyle } from 'react-native';
|
|
6
6
|
import { StyleSheet } from 'react-native-unistyles';
|
|
7
|
-
import {
|
|
7
|
+
import { BodyText } from '../BodyText';
|
|
8
8
|
import ExpandableCardContent from './ExpandableCardContent';
|
|
9
9
|
import ExpandableCardHelperText from './ExpandableCardHelperText';
|
|
10
10
|
import ExpandableCardIcon from './ExpandableCardIcon';
|
|
@@ -62,10 +62,10 @@ const ExpandableCardTriggerRoot = ({
|
|
|
62
62
|
{helperText && <ExpandableCardHelperText>{helperText}</ExpandableCardHelperText>}
|
|
63
63
|
{badgePosition === 'bottom' ? badge : null}
|
|
64
64
|
</ExpandableCardContent>
|
|
65
|
-
{numericValue && (
|
|
66
|
-
<
|
|
65
|
+
{!!numericValue && (
|
|
66
|
+
<BodyText weight="semibold" style={styles.numericValue}>
|
|
67
67
|
{numericValue}
|
|
68
|
-
</
|
|
68
|
+
</BodyText>
|
|
69
69
|
)}
|
|
70
70
|
<ExpandableCardTrailingContent style={styles.chevron}>
|
|
71
71
|
<ExpandableCardTrailingIcon as={isExpanded ? ChevronUpSmallIcon : ChevronDownSmallIcon} />
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Canvas, Controls, Meta, Primary, Story } from '@storybook/addon-docs/blocks';
|
|
2
|
+
import { Box, Center, Heading, Pressable } from '../../';
|
|
3
|
+
import { BackToTopButton, UsageWrap, ViewFigmaButton } from '../../../docs/components';
|
|
2
4
|
import * as Stories from './Heading.stories';
|
|
3
|
-
import { Center, Pressable, Heading, Box } from '../../';
|
|
4
|
-
import { UsageWrap, BackToTopButton, ViewFigmaButton } from '../../../docs/components';
|
|
5
5
|
|
|
6
6
|
<Meta title="Typography / Heading" />
|
|
7
7
|
|
|
@@ -17,6 +17,7 @@ The `Heading` component gives you the ability to create headings for your screen
|
|
|
17
17
|
- [Usage](#usage)
|
|
18
18
|
- [Props](#props)
|
|
19
19
|
- [Sizes](#sizes)
|
|
20
|
+
- [Accessibility](#accessibility)
|
|
20
21
|
|
|
21
22
|
## Playground
|
|
22
23
|
|
|
@@ -60,3 +61,11 @@ const MyComponent = () => <Heading>Welcome to Utility Warehouse</Heading>;
|
|
|
60
61
|
The `Heading` component has different sizes to style the text.
|
|
61
62
|
|
|
62
63
|
<Canvas of={Stories.KitchenSink} />
|
|
64
|
+
|
|
65
|
+
## Accessibility
|
|
66
|
+
|
|
67
|
+
`Heading` sets `accessibilityRole="header"` by default, so VoiceOver and TalkBack can announce it as a heading without any extra configuration.
|
|
68
|
+
If you need to override this behavior, pass an explicit `accessibilityRole` prop (for example, `accessibilityRole="text"`) to opt out of heading semantics.
|
|
69
|
+
|
|
70
|
+
- Use `Heading` for actual screen or section titles so assistive technologies can expose the right document structure.
|
|
71
|
+
- If you need styled text without heading semantics, either override the `accessibilityRole` on `Heading` or use one of the other text components instead.
|
|
@@ -383,7 +383,7 @@ const MyComponent = () => (
|
|
|
383
383
|
trailingContent={
|
|
384
384
|
<>
|
|
385
385
|
<BodyText>-£100.00</BodyText>
|
|
386
|
-
<BodyText color="
|
|
386
|
+
<BodyText color="brand">-£100.00</BodyText>
|
|
387
387
|
</>
|
|
388
388
|
}
|
|
389
389
|
onPress={() => console.log('Transaction pressed')}
|
|
@@ -393,7 +393,7 @@ const MyComponent = () => (
|
|
|
393
393
|
helperText="Apr 4, 2024"
|
|
394
394
|
trailingContent={
|
|
395
395
|
<>
|
|
396
|
-
<BodyText color="
|
|
396
|
+
<BodyText color="affirmative">+£100.00</BodyText>
|
|
397
397
|
</>
|
|
398
398
|
}
|
|
399
399
|
onPress={() => console.log('Transaction pressed')}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Meta, StoryObj } from '@storybook/react-
|
|
1
|
+
import { Meta, StoryObj } from '@storybook/react-native';
|
|
2
2
|
import {
|
|
3
3
|
BillMediumIcon,
|
|
4
4
|
ChevronRightSmallIcon,
|
|
@@ -60,7 +60,7 @@ export default meta;
|
|
|
60
60
|
type Story = StoryObj<typeof meta>;
|
|
61
61
|
|
|
62
62
|
export const Playground: Story = {
|
|
63
|
-
render: ({ container, ...args }) => {
|
|
63
|
+
render: ({ container, ...args }: StoryObj<typeof meta.args>) => {
|
|
64
64
|
return (
|
|
65
65
|
<List {...args} container={container}>
|
|
66
66
|
{Array.from({ length: 4 }).map((_, index) => (
|
|
@@ -75,7 +75,7 @@ export const WithAction: Story = {
|
|
|
75
75
|
args: {
|
|
76
76
|
container: 'subtleWhite',
|
|
77
77
|
},
|
|
78
|
-
render: ({ container, ...args }) => (
|
|
78
|
+
render: ({ container, ...args }: StoryObj<typeof meta.args>) => (
|
|
79
79
|
<List {...args} container={container}>
|
|
80
80
|
{Array.from({ length: 4 }).map((_, index) => (
|
|
81
81
|
<ListItem key={index} heading="List item text" helperText="Supporting text" />
|
|
@@ -292,6 +292,7 @@ export const WithListAction: Story = {
|
|
|
292
292
|
heading="Manage payment methods"
|
|
293
293
|
helperText="Update your credit or debit cards"
|
|
294
294
|
onPress={() => console.log('Manage pressed')}
|
|
295
|
+
accessibilityRole="link"
|
|
295
296
|
/>
|
|
296
297
|
<ListAction heading="Contact support" onPress={() => console.log('Contact pressed')} />
|
|
297
298
|
</List>
|
|
@@ -310,7 +311,7 @@ export const WithTransactions: Story = {
|
|
|
310
311
|
trailingContent={
|
|
311
312
|
<>
|
|
312
313
|
<BodyText>-£100.00</BodyText>
|
|
313
|
-
<BodyText color="
|
|
314
|
+
<BodyText color="brand">+£1.00 CB</BodyText>
|
|
314
315
|
</>
|
|
315
316
|
}
|
|
316
317
|
onPress={() => console.log('Transaction pressed')}
|
|
@@ -320,7 +321,7 @@ export const WithTransactions: Story = {
|
|
|
320
321
|
helperText="Apr 4, 2024"
|
|
321
322
|
trailingContent={
|
|
322
323
|
<>
|
|
323
|
-
<BodyText color="
|
|
324
|
+
<BodyText color="affirmative">+£100.00</BodyText>
|
|
324
325
|
</>
|
|
325
326
|
}
|
|
326
327
|
onPress={() => console.log('Transaction pressed')}
|
|
@@ -14,7 +14,15 @@ const List = ({
|
|
|
14
14
|
invalidText,
|
|
15
15
|
...props
|
|
16
16
|
}: ListProps) => {
|
|
17
|
-
const {
|
|
17
|
+
const {
|
|
18
|
+
loading,
|
|
19
|
+
disabled,
|
|
20
|
+
container = 'none',
|
|
21
|
+
testID,
|
|
22
|
+
style,
|
|
23
|
+
accessibilityRole,
|
|
24
|
+
...rest
|
|
25
|
+
} = props;
|
|
18
26
|
|
|
19
27
|
const orderRef = useRef<string[]>([]);
|
|
20
28
|
const [firstItemId, setFirstItemId] = useState<string | undefined>(undefined);
|
|
@@ -52,7 +60,11 @@ const List = ({
|
|
|
52
60
|
styles.useVariants({ disabled });
|
|
53
61
|
return (
|
|
54
62
|
<ListContext.Provider value={value}>
|
|
55
|
-
<View
|
|
63
|
+
<View
|
|
64
|
+
{...rest}
|
|
65
|
+
accessibilityRole={accessibilityRole ?? 'list'}
|
|
66
|
+
style={[styles.container, style]}
|
|
67
|
+
>
|
|
56
68
|
{heading ? (
|
|
57
69
|
<SectionHeader
|
|
58
70
|
heading={heading}
|
|
@@ -2,7 +2,7 @@ import { ChevronRightSmallIcon } from '@utilitywarehouse/hearth-react-native-ico
|
|
|
2
2
|
import { useId, useLayoutEffect, useMemo } from 'react';
|
|
3
3
|
import { Pressable, ViewStyle } from 'react-native';
|
|
4
4
|
import { StyleSheet } from 'react-native-unistyles';
|
|
5
|
-
import {
|
|
5
|
+
import { BodyText } from '../../BodyText';
|
|
6
6
|
import { Skeleton } from '../../Skeleton';
|
|
7
7
|
import { useListContext } from '../List.context';
|
|
8
8
|
import { IListItemContext, ListItemContext } from './ListItem.context';
|
|
@@ -109,7 +109,7 @@ const ListItemRoot = ({
|
|
|
109
109
|
testID={testID}
|
|
110
110
|
style={[styles.container, props.style as ViewStyle]}
|
|
111
111
|
disabled={isDisabled}
|
|
112
|
-
accessibilityRole={onPress ? 'button' : undefined}
|
|
112
|
+
accessibilityRole={props.accessibilityRole ?? (onPress ? 'button' : undefined)}
|
|
113
113
|
>
|
|
114
114
|
{children ? (
|
|
115
115
|
children
|
|
@@ -126,7 +126,7 @@ const ListItemRoot = ({
|
|
|
126
126
|
) : null}
|
|
127
127
|
{badgePosition === 'bottom' && badge ? badge : null}
|
|
128
128
|
</ListItemContent>
|
|
129
|
-
{!!numericValue && <
|
|
129
|
+
{!!numericValue && <BodyText weight="semibold">{numericValue}</BodyText>}
|
|
130
130
|
{trailingContent ? (
|
|
131
131
|
<ListItemTrailingContent>{trailingContent}</ListItemTrailingContent>
|
|
132
132
|
) : onPress ? (
|
|
@@ -87,27 +87,28 @@ const MyComponent = () => {
|
|
|
87
87
|
|
|
88
88
|
The Modal component extends the `BottomSheetModal` component and accepts all of its props, plus the following additional props:
|
|
89
89
|
|
|
90
|
-
| Property | Type | Description
|
|
91
|
-
| ----------------------------- | ------------------------------------------------------------------ |
|
|
92
|
-
| `heading` | `string` | The heading text displayed at the top of the modal
|
|
93
|
-
| `description` | `string` | The description text displayed below the heading
|
|
94
|
-
| `showCloseButton` | `boolean` | Whether to show the close button in the top-right corner
|
|
95
|
-
| `primaryButtonText` | `string` | Text for the primary action button
|
|
96
|
-
| `secondaryButtonText` | `string` | Text for the secondary action button
|
|
97
|
-
| `onPressPrimaryButton` | `() => void` | Callback function called when the primary button is pressed
|
|
98
|
-
| `onPressSecondaryButton` | `() => void` | Callback function called when the secondary button is pressed
|
|
99
|
-
| `onPressCloseButton` | `() => void` | Callback function called when the close button is pressed
|
|
100
|
-
| `closeOnPrimaryButtonPress` | `boolean` | Whether to automatically close the modal when the primary button is pressed
|
|
101
|
-
| `closeOnSecondaryButtonPress` | `boolean` | Whether to automatically close the modal when the secondary button is pressed
|
|
102
|
-
| `onChange` | `(index: number, position: number, `<br />` type: number) => void` | Callback function called when the modal's position changes \*
|
|
103
|
-
| `loading` | `boolean` | Whether to show a loading state with spinner
|
|
104
|
-
| `loadingHeading` | `string` | The heading text to be displayed when loading is true. If not provided, the regular heading will be shown.
|
|
105
|
-
| `
|
|
106
|
-
| `
|
|
107
|
-
| `
|
|
108
|
-
| `
|
|
109
|
-
| `
|
|
110
|
-
| `
|
|
90
|
+
| Property | Type | Description | Default |
|
|
91
|
+
| ----------------------------- | ------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------ | -------------- |
|
|
92
|
+
| `heading` | `string` | The heading text displayed at the top of the modal | - |
|
|
93
|
+
| `description` | `string` | The description text displayed below the heading | - |
|
|
94
|
+
| `showCloseButton` | `boolean` | Whether to show the close button in the top-right corner | `true` |
|
|
95
|
+
| `primaryButtonText` | `string` | Text for the primary action button | - |
|
|
96
|
+
| `secondaryButtonText` | `string` | Text for the secondary action button | - |
|
|
97
|
+
| `onPressPrimaryButton` | `() => void` | Callback function called when the primary button is pressed | - |
|
|
98
|
+
| `onPressSecondaryButton` | `() => void` | Callback function called when the secondary button is pressed | - |
|
|
99
|
+
| `onPressCloseButton` | `() => void` | Callback function called when the close button is pressed | - |
|
|
100
|
+
| `closeOnPrimaryButtonPress` | `boolean` | Whether to automatically close the modal when the primary button is pressed | `true` |
|
|
101
|
+
| `closeOnSecondaryButtonPress` | `boolean` | Whether to automatically close the modal when the secondary button is pressed | `true` |
|
|
102
|
+
| `onChange` | `(index: number, position: number, `<br />` type: number) => void` | Callback function called when the modal's position changes \* | - |
|
|
103
|
+
| `loading` | `boolean` | Whether to show a loading state with spinner | `false` |
|
|
104
|
+
| `loadingHeading` | `string` | The heading text to be displayed when loading is true. If not provided, the regular heading will be shown. | `'Loading...'` |
|
|
105
|
+
| `loadingDescription` | `string` | The description text to be displayed when loading is true. If not provided, the regular description will be shown. | - |
|
|
106
|
+
| `image` | `ImageProps` | Image to display in the modal (shows as centered content with text below) | - |
|
|
107
|
+
| `children` | `ReactNode` | Custom content to display in the modal body | - |
|
|
108
|
+
| `primaryButtonProps` | `Omit<ButtonWithoutChildrenProps, 'children'>` | Additional props to pass to the primary button (colorScheme defaults to 'highlight', variant to 'solid') | - |
|
|
109
|
+
| `secondaryButtonProps` | `Omit<ButtonWithoutChildrenProps, 'children'>` | Additional props to pass to the secondary button (colorScheme defaults to 'functional', variant to 'outline') | - |
|
|
110
|
+
| `closeButtonProps` | `Omit<UnstyledIconButtonProps, 'children'>` | Additional props to pass to the close button | - |
|
|
111
|
+
| `fullscreen` | `boolean` | Whether the modal should take up the full screen height | `false` |
|
|
111
112
|
|
|
112
113
|
\* use this to detect if the modal has been opened or closed, index 0 indicates open state and -1 indicates closed state
|
|
113
114
|
|
|
@@ -476,6 +477,20 @@ const App = () => {
|
|
|
476
477
|
};
|
|
477
478
|
```
|
|
478
479
|
|
|
480
|
+
If your app already handles safe-area padding around modal content, you can disable Hearth's bottom-sheet safe-area spacing:
|
|
481
|
+
|
|
482
|
+
```tsx
|
|
483
|
+
import { BottomSheetModalProvider } from '@utilitywarehouse/hearth-react-native';
|
|
484
|
+
|
|
485
|
+
const App = () => {
|
|
486
|
+
return (
|
|
487
|
+
<BottomSheetModalProvider useSafeAreaInsets={false}>
|
|
488
|
+
{/* Your app content */}
|
|
489
|
+
</BottomSheetModalProvider>
|
|
490
|
+
);
|
|
491
|
+
};
|
|
492
|
+
```
|
|
493
|
+
|
|
479
494
|
### Ref Usage
|
|
480
495
|
|
|
481
496
|
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';
|
|
@@ -34,6 +35,7 @@ const Modal = ({
|
|
|
34
35
|
closeOnSecondaryButtonPress = true,
|
|
35
36
|
loading,
|
|
36
37
|
loadingHeading = 'Loading...',
|
|
38
|
+
loadingDescription,
|
|
37
39
|
fullscreen = false,
|
|
38
40
|
image,
|
|
39
41
|
primaryButtonProps,
|
|
@@ -45,6 +47,7 @@ const Modal = ({
|
|
|
45
47
|
const bottomSheetModalRef = useRef<BottomSheetModal>(null);
|
|
46
48
|
const viewRef = useRef<View>(null);
|
|
47
49
|
const scrollViewRef = useRef<BottomSheetScrollViewMethods>(null);
|
|
50
|
+
const { useSafeAreaInsets } = useBottomSheetContext();
|
|
48
51
|
|
|
49
52
|
useImperativeHandle(ref, () => ({
|
|
50
53
|
...(bottomSheetModalRef.current as BottomSheetModal),
|
|
@@ -105,6 +108,7 @@ const Modal = ({
|
|
|
105
108
|
noButtons,
|
|
106
109
|
stickyFooter,
|
|
107
110
|
showHandle: props.showHandle,
|
|
111
|
+
useSafeAreaInsets,
|
|
108
112
|
});
|
|
109
113
|
|
|
110
114
|
const footer = useMemo(
|
|
@@ -148,7 +152,10 @@ const Modal = ({
|
|
|
148
152
|
<View
|
|
149
153
|
style={styles.loadingContainer}
|
|
150
154
|
accessible={Platform.OS === 'android' ? true : undefined}
|
|
151
|
-
accessibilityLabel={Platform.OS === 'android' ? 'Loading' : undefined}
|
|
155
|
+
accessibilityLabel={Platform.OS === 'android' ? (loadingHeading ?? 'Loading') : undefined}
|
|
156
|
+
accessibilityHint={
|
|
157
|
+
Platform.OS === 'android' && loadingDescription ? loadingDescription : undefined
|
|
158
|
+
}
|
|
152
159
|
screenReaderFocusable
|
|
153
160
|
ref={viewRef}
|
|
154
161
|
>
|
|
@@ -156,6 +163,7 @@ const Modal = ({
|
|
|
156
163
|
<Heading size="lg" textAlign="center">
|
|
157
164
|
{loadingHeading}
|
|
158
165
|
</Heading>
|
|
166
|
+
{loadingDescription ? <BodyText textAlign="center">{loadingDescription}</BodyText> : null}
|
|
159
167
|
</View>
|
|
160
168
|
) : (
|
|
161
169
|
<View
|
|
@@ -256,13 +264,44 @@ const styles = StyleSheet.create((theme, rt) => ({
|
|
|
256
264
|
variants: {
|
|
257
265
|
bothButtons: {
|
|
258
266
|
true: {
|
|
267
|
+
paddingBottom: 166,
|
|
268
|
+
},
|
|
269
|
+
false: {
|
|
270
|
+
paddingBottom: 102,
|
|
271
|
+
},
|
|
272
|
+
},
|
|
273
|
+
noButtons: {
|
|
274
|
+
true: {
|
|
275
|
+
paddingBottom: theme.components.modal.padding,
|
|
276
|
+
},
|
|
277
|
+
},
|
|
278
|
+
stickyFooter: {
|
|
279
|
+
true: {},
|
|
280
|
+
false: {
|
|
281
|
+
paddingBottom: theme.components.modal.padding + theme.components.bottomSheet.padding,
|
|
282
|
+
},
|
|
283
|
+
},
|
|
284
|
+
useSafeAreaInsets: {
|
|
285
|
+
true: {},
|
|
286
|
+
false: {},
|
|
287
|
+
},
|
|
288
|
+
},
|
|
289
|
+
compoundVariants: [
|
|
290
|
+
{
|
|
291
|
+
bothButtons: true,
|
|
292
|
+
useSafeAreaInsets: true,
|
|
293
|
+
styles: {
|
|
259
294
|
paddingBottom:
|
|
260
295
|
166 +
|
|
261
296
|
rt.insets.bottom -
|
|
262
297
|
theme.components.modal.padding +
|
|
263
298
|
theme.components.bottomSheet.padding,
|
|
264
299
|
},
|
|
265
|
-
|
|
300
|
+
},
|
|
301
|
+
{
|
|
302
|
+
bothButtons: false,
|
|
303
|
+
useSafeAreaInsets: true,
|
|
304
|
+
styles: {
|
|
266
305
|
paddingBottom:
|
|
267
306
|
102 +
|
|
268
307
|
rt.insets.bottom -
|
|
@@ -270,24 +309,27 @@ const styles = StyleSheet.create((theme, rt) => ({
|
|
|
270
309
|
theme.components.bottomSheet.padding,
|
|
271
310
|
},
|
|
272
311
|
},
|
|
273
|
-
|
|
274
|
-
|
|
312
|
+
{
|
|
313
|
+
noButtons: true,
|
|
314
|
+
useSafeAreaInsets: true,
|
|
315
|
+
styles: {
|
|
275
316
|
paddingBottom:
|
|
276
317
|
rt.insets.bottom +
|
|
277
318
|
theme.components.modal.padding +
|
|
278
319
|
theme.components.bottomSheet.padding,
|
|
279
320
|
},
|
|
280
321
|
},
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
322
|
+
{
|
|
323
|
+
useSafeAreaInsets: true,
|
|
324
|
+
stickyFooter: false,
|
|
325
|
+
styles: {
|
|
284
326
|
paddingBottom:
|
|
285
327
|
rt.insets.bottom +
|
|
286
328
|
theme.components.modal.padding +
|
|
287
329
|
theme.components.bottomSheet.padding,
|
|
288
330
|
},
|
|
289
331
|
},
|
|
290
|
-
|
|
332
|
+
],
|
|
291
333
|
},
|
|
292
334
|
header: {
|
|
293
335
|
flexDirection: 'row',
|
|
@@ -333,7 +375,16 @@ const styles = StyleSheet.create((theme, rt) => ({
|
|
|
333
375
|
footerWrap: {
|
|
334
376
|
backgroundColor: theme.color.surface.neutral.strong,
|
|
335
377
|
paddingHorizontal: theme.components.bottomSheet.padding,
|
|
336
|
-
|
|
378
|
+
variants: {
|
|
379
|
+
useSafeAreaInsets: {
|
|
380
|
+
true: {
|
|
381
|
+
paddingBottom: theme.components.bottomSheet.padding + rt.insets.bottom,
|
|
382
|
+
},
|
|
383
|
+
false: {
|
|
384
|
+
paddingBottom: theme.components.bottomSheet.padding,
|
|
385
|
+
},
|
|
386
|
+
},
|
|
387
|
+
},
|
|
337
388
|
},
|
|
338
389
|
}));
|
|
339
390
|
|
|
@@ -150,6 +150,7 @@ const styles = StyleSheet.create({
|
|
|
150
150
|
| `closeButtonProps` | `Omit<UnstyledIconButtonProps, 'children'>` | Extra props forwarded to the close button. | - |
|
|
151
151
|
| `loading` | `boolean` | Replaces the content with a loading state and spinner. | `false` |
|
|
152
152
|
| `loadingHeading` | `string` | Heading text shown while `loading` is true. | `'Loading...'` |
|
|
153
|
+
| `loadingDescription` | `string` | Supporting text shown below the heading while `loading` is true. | - |
|
|
153
154
|
| `image` | `ReactNode` | Optional image or illustration shown above the text content. | - |
|
|
154
155
|
| `children` | `ReactNode` | Content rendered inside the modal body. | - |
|
|
155
156
|
| `stickyFooter` | `boolean` | Keeps action buttons pinned to the bottom instead of flowing with the content. | `true` |
|
|
@@ -32,6 +32,7 @@ const NavModal = ({
|
|
|
32
32
|
onPressSecondaryButton,
|
|
33
33
|
loading,
|
|
34
34
|
loadingHeading = 'Loading...',
|
|
35
|
+
loadingDescription,
|
|
35
36
|
image,
|
|
36
37
|
primaryButtonProps,
|
|
37
38
|
secondaryButtonProps,
|
|
@@ -162,13 +163,21 @@ const NavModal = ({
|
|
|
162
163
|
<View
|
|
163
164
|
style={styles.loadingContainer}
|
|
164
165
|
accessible={Platform.OS === 'android' ? true : undefined}
|
|
165
|
-
accessibilityLabel={Platform.OS === 'android' ? 'Loading' : undefined}
|
|
166
|
+
accessibilityLabel={Platform.OS === 'android' ? (loadingHeading ?? 'Loading') : undefined}
|
|
167
|
+
accessibilityHint={
|
|
168
|
+
Platform.OS === 'android' && loadingDescription ? loadingDescription : undefined
|
|
169
|
+
}
|
|
166
170
|
screenReaderFocusable
|
|
167
171
|
>
|
|
168
172
|
<Spinner size="lg" color={isBrandBackground ? theme.color.icon.inverted : undefined} />
|
|
169
173
|
<Heading size="lg" textAlign="center" inverted={isBrandBackground}>
|
|
170
174
|
{loadingHeading}
|
|
171
175
|
</Heading>
|
|
176
|
+
{loadingDescription ? (
|
|
177
|
+
<BodyText size="md" textAlign="center" inverted={isBrandBackground}>
|
|
178
|
+
{loadingDescription}
|
|
179
|
+
</BodyText>
|
|
180
|
+
) : null}
|
|
172
181
|
</View>
|
|
173
182
|
) : (
|
|
174
183
|
<View
|
|
@@ -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>
|