@utilitywarehouse/hearth-react-native 0.28.1 → 0.28.3
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 +12 -0
- package/build/components/Combobox/Combobox.js +4 -5
- package/build/components/Select/Select.js +1 -1
- package/docs/adding-shadows.mdx +26 -2
- package/docs/all-components.mdx +2 -2
- package/docs/changelog.mdx +12 -0
- package/docs/components/InputShadowExample.tsx +19 -0
- package/docs/components/index.ts +1 -0
- package/package.json +2 -2
- package/src/components/Checkbox/Checkbox.docs.mdx +40 -0
- package/src/components/Combobox/Combobox.tsx +5 -7
- package/src/components/Modal/Modal.docs.mdx +39 -18
- package/src/components/Radio/Radio.docs.mdx +40 -0
- package/src/components/Select/Select.tsx +4 -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.28.
|
|
2
|
+
> @utilitywarehouse/hearth-react-native@0.28.3 lint /home/runner/work/hearth/hearth/packages/react-native
|
|
3
3
|
> TIMING=1 eslint .
|
|
4
4
|
|
|
5
5
|
|
|
@@ -54,15 +54,15 @@
|
|
|
54
54
|
|
|
55
55
|
✖ 23 problems (0 errors, 23 warnings)
|
|
56
56
|
|
|
57
|
-
Rule
|
|
58
|
-
|
|
59
|
-
@typescript-eslint/no-unused-vars
|
|
60
|
-
react-hooks/exhaustive-deps
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
@typescript-eslint/ban-ts-comment
|
|
64
|
-
no-
|
|
65
|
-
no-
|
|
66
|
-
no-
|
|
67
|
-
no-
|
|
68
|
-
|
|
57
|
+
Rule | Time (ms) | Relative
|
|
58
|
+
:-----------------------------------------|----------:|--------:
|
|
59
|
+
@typescript-eslint/no-unused-vars | 1554.353 | 59.2%
|
|
60
|
+
react-hooks/exhaustive-deps | 144.027 | 5.5%
|
|
61
|
+
no-global-assign | 113.457 | 4.3%
|
|
62
|
+
react-hooks/rules-of-hooks | 91.927 | 3.5%
|
|
63
|
+
@typescript-eslint/ban-ts-comment | 60.650 | 2.3%
|
|
64
|
+
no-fallthrough | 48.638 | 1.9%
|
|
65
|
+
no-unexpected-multiline | 47.691 | 1.8%
|
|
66
|
+
no-misleading-character-class | 45.726 | 1.7%
|
|
67
|
+
@typescript-eslint/no-unused-expressions | 29.696 | 1.1%
|
|
68
|
+
@typescript-eslint/triple-slash-reference | 29.272 | 1.1%
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @utilitywarehouse/hearth-react-native
|
|
2
2
|
|
|
3
|
+
## 0.28.3
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#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.
|
|
8
|
+
|
|
9
|
+
## 0.28.2
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- [#1024](https://github.com/utilitywarehouse/hearth/pull/1024) [`23b6767`](https://github.com/utilitywarehouse/hearth/commit/23b67672b89198a483ddcef88f9c6207b684c4d9) Thanks [@fillyD](https://github.com/fillyD)! - 🐛 [FIX]: Adds missing `testID` to `Select` component
|
|
14
|
+
|
|
3
15
|
## 0.28.1
|
|
4
16
|
|
|
5
17
|
### Patch Changes
|
|
@@ -10,10 +10,10 @@ import { DetailText } from '../DetailText';
|
|
|
10
10
|
import { FormField, useFormFieldContext } from '../FormField';
|
|
11
11
|
import { Icon } from '../Icon';
|
|
12
12
|
import { Input } from '../Input';
|
|
13
|
+
import { SafeAreaView } from '../SafeAreaView';
|
|
13
14
|
import { Spinner } from '../Spinner';
|
|
14
15
|
import { UnstyledIconButton } from '../UnstyledIconButton';
|
|
15
16
|
import { ComboboxContext } from './Combobox.context';
|
|
16
|
-
import { SafeAreaView } from '../SafeAreaView';
|
|
17
17
|
import ComboboxOption from './ComboboxOption';
|
|
18
18
|
const DEFAULT_SNAP_POINTS = ['25%', '40%', '80%'];
|
|
19
19
|
const Combobox = ({ options = [], value, onValueChange, inputValue, onInputValueChange, label, labelVariant = 'body', placeholder = 'Search', searchPlaceholder = 'Search', disabled = false, validationStatus = 'initial', helperText, helperIcon, invalidText, validText, required = true, children, bottomSheetProps, menuHeading, noOptionsFoundText = 'No options found', listProps, loading = false, readonly = false, getValueLabel, filterOption, ...rest }) => {
|
|
@@ -178,9 +178,6 @@ const styles = StyleSheet.create(theme => ({
|
|
|
178
178
|
borderRadius: theme.components.input.borderRadius,
|
|
179
179
|
paddingHorizontal: theme.components.input.paddingHorizontal,
|
|
180
180
|
gap: theme.components.input.gap,
|
|
181
|
-
outlineStyle: 'solid',
|
|
182
|
-
outlineWidth: theme.components.input.borderWidth,
|
|
183
|
-
outlineColor: theme.color.border.strong,
|
|
184
181
|
variants: {
|
|
185
182
|
disabled: {
|
|
186
183
|
true: {
|
|
@@ -206,7 +203,9 @@ const styles = StyleSheet.create(theme => ({
|
|
|
206
203
|
},
|
|
207
204
|
},
|
|
208
205
|
triggerFocused: {
|
|
209
|
-
|
|
206
|
+
outlineStyle: 'solid',
|
|
207
|
+
outlineWidth: theme.components.input.borderWidth,
|
|
208
|
+
outlineColor: theme.color.border.strong,
|
|
210
209
|
},
|
|
211
210
|
leadingIconContainer: {
|
|
212
211
|
alignItems: 'center',
|
|
@@ -77,7 +77,7 @@ const Select = ({ options = [], value, onValueChange, label, labelVariant = 'bod
|
|
|
77
77
|
selectedValue: value,
|
|
78
78
|
onValueChange,
|
|
79
79
|
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, { children: children })) : (_jsx(BottomSheetFlatList, { data: filteredOptions, keyExtractor: (option) => option.value, renderItem: renderSelectOption, ListEmptyComponent: renderEmptyComponent, ...listProps }))] }) }) })] }));
|
|
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 }))] }) }) })] }));
|
|
81
81
|
};
|
|
82
82
|
const styles = StyleSheet.create(theme => ({
|
|
83
83
|
container: {
|
package/docs/adding-shadows.mdx
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Meta } from '@storybook/addon-docs/blocks';
|
|
2
|
-
import {
|
|
2
|
+
import { BodyText, Box, Card, Center, Heading } from '../src';
|
|
3
|
+
import { BackToTopButton, InputShadowExample, NextPrevPage, UsageWrap } from './components';
|
|
3
4
|
|
|
4
5
|
<Meta title="Guides / Adding Shadows" />
|
|
5
6
|
<BackToTopButton />
|
|
@@ -15,9 +16,16 @@ You can add shadows to your components in Hearth React Native using the Unistyle
|
|
|
15
16
|
|
|
16
17
|
Hearth provides a set of predefined shadow styles that you can easily apply to your components. These shadows are defined in the theme and can be accessed via the `theme.helpers.shadow` object.
|
|
17
18
|
|
|
19
|
+
<UsageWrap>
|
|
20
|
+
<Center>
|
|
21
|
+
<InputShadowExample />
|
|
22
|
+
</Center>
|
|
23
|
+
</UsageWrap>
|
|
24
|
+
|
|
18
25
|
```tsx
|
|
19
26
|
import { View } from 'react-native';
|
|
20
27
|
import { StyleSheet, Input } from '@utilitywarehouse/hearth-react-native';
|
|
28
|
+
import { SearchMediumIcon } from '@utilitywarehouse/hearth-react-native-icons';
|
|
21
29
|
|
|
22
30
|
const styles = StyleSheet.create(theme => ({
|
|
23
31
|
input: {
|
|
@@ -27,13 +35,22 @@ const styles = StyleSheet.create(theme => ({
|
|
|
27
35
|
|
|
28
36
|
const MyComponent = () => (
|
|
29
37
|
<View>
|
|
30
|
-
<Input placeholder="Input with shadow" style={styles.input} />
|
|
38
|
+
<Input placeholder="Input with shadow" style={styles.input} leadingIcon={SearchMediumIcon} />
|
|
31
39
|
</View>
|
|
32
40
|
);
|
|
33
41
|
```
|
|
34
42
|
|
|
35
43
|
## Components with Shadow Props
|
|
36
44
|
|
|
45
|
+
<UsageWrap>
|
|
46
|
+
<Center>
|
|
47
|
+
<Card shadowColor="brand" spacing="md">
|
|
48
|
+
<Heading size="md">Card with Shadow</Heading>
|
|
49
|
+
<BodyText>This card has a shadow color set to the brand color.</BodyText>
|
|
50
|
+
</Card>
|
|
51
|
+
</Center>
|
|
52
|
+
</UsageWrap>
|
|
53
|
+
|
|
37
54
|
Some Hearth components, like `Card`, allow you to specify shadow colors directly via props. You can use the `shadowColor` prop to set the shadow color based on the theme.
|
|
38
55
|
|
|
39
56
|
```tsx
|
|
@@ -41,3 +58,10 @@ import { Card } from '@utilitywarehouse/hearth-react-native';
|
|
|
41
58
|
|
|
42
59
|
const MyComponent = () => <Card shadowColor="brand">{/* Card content */}</Card>;
|
|
43
60
|
```
|
|
61
|
+
|
|
62
|
+
<NextPrevPage
|
|
63
|
+
prevLink="all-components"
|
|
64
|
+
prevTitle="All Components"
|
|
65
|
+
nextLink="primitives-box"
|
|
66
|
+
nextTitle="Box"
|
|
67
|
+
/>
|
package/docs/all-components.mdx
CHANGED
|
@@ -14,6 +14,6 @@ This page showcases all the components available in the Hearth React Native libr
|
|
|
14
14
|
<NextPrevPage
|
|
15
15
|
prevLink="layout-components"
|
|
16
16
|
prevTitle="Layout Components"
|
|
17
|
-
nextLink="
|
|
18
|
-
nextTitle="
|
|
17
|
+
nextLink="guides-adding-shadows"
|
|
18
|
+
nextTitle="Adding Shadows"
|
|
19
19
|
/>
|
package/docs/changelog.mdx
CHANGED
|
@@ -9,6 +9,18 @@ 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.2
|
|
13
|
+
|
|
14
|
+
### Patch Changes
|
|
15
|
+
|
|
16
|
+
- [#1024](https://github.com/utilitywarehouse/hearth/pull/1024) [`23b6767`](https://github.com/utilitywarehouse/hearth/commit/23b67672b89198a483ddcef88f9c6207b684c4d9) Thanks [@fillyD](https://github.com/fillyD)! - 🐛 [FIX]: Adds missing `testID` to `Select` component
|
|
17
|
+
|
|
18
|
+
## 0.28.1
|
|
19
|
+
|
|
20
|
+
### Patch Changes
|
|
21
|
+
|
|
22
|
+
- [#1018](https://github.com/utilitywarehouse/hearth/pull/1018) [`1c5e02e`](https://github.com/utilitywarehouse/hearth/commit/1c5e02ea4b61329e7c55e52f9aa4ae44abc0da23) Thanks [@fillyD](https://github.com/fillyD)! - 🐛 [FIX]: Adds missing `testID` to `Select`, `SelectOption` and `VerificationInput` component
|
|
23
|
+
|
|
12
24
|
## 0.28.0
|
|
13
25
|
|
|
14
26
|
### Minor Changes
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { SearchMediumIcon } from '@utilitywarehouse/hearth-react-native-icons';
|
|
2
|
+
import { StyleSheet } from 'react-native-unistyles';
|
|
3
|
+
import { Box, Input } from '../../src';
|
|
4
|
+
|
|
5
|
+
const InputShadowExample = () => {
|
|
6
|
+
return (
|
|
7
|
+
<Box padding="md">
|
|
8
|
+
<Input placeholder="Input with shadow" style={styles.input} leadingIcon={SearchMediumIcon} />
|
|
9
|
+
</Box>
|
|
10
|
+
);
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const styles = StyleSheet.create(theme => ({
|
|
14
|
+
input: {
|
|
15
|
+
boxShadow: theme.helpers.shadow.functional,
|
|
16
|
+
},
|
|
17
|
+
}));
|
|
18
|
+
|
|
19
|
+
export default InputShadowExample;
|
package/docs/components/index.ts
CHANGED
|
@@ -3,6 +3,7 @@ export { default as AdvancedInputExample } from './AdvancedInputExample';
|
|
|
3
3
|
export { default as BackToTopButton } from './BackToTopButton';
|
|
4
4
|
export { default as BadgeList } from './BadgeList';
|
|
5
5
|
export { default as DocComponentWrap } from './DocComponentWrap';
|
|
6
|
+
export { default as InputShadowExample } from './InputShadowExample';
|
|
6
7
|
export { default as NextPrevPage } from './NextPrevPage';
|
|
7
8
|
export { default as SwitchExample } from './SwitchExample';
|
|
8
9
|
export { default as SwitchList } from './SwitchList';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@utilitywarehouse/hearth-react-native",
|
|
3
|
-
"version": "0.28.
|
|
3
|
+
"version": "0.28.3",
|
|
4
4
|
"description": "Utility Warehouse React Native UI library",
|
|
5
5
|
"main": "build/index.js",
|
|
6
6
|
"types": "build/index.d.ts",
|
|
@@ -57,8 +57,8 @@
|
|
|
57
57
|
"vite-plugin-svgr": "^4.5.0",
|
|
58
58
|
"vitest": "^3.2.4",
|
|
59
59
|
"@utilitywarehouse/hearth-fonts": "^0.0.4",
|
|
60
|
-
"@utilitywarehouse/hearth-react-native-icons": "^0.8.0",
|
|
61
60
|
"@utilitywarehouse/hearth-react-icons": "^0.8.0",
|
|
61
|
+
"@utilitywarehouse/hearth-react-native-icons": "^0.8.0",
|
|
62
62
|
"@utilitywarehouse/hearth-svg-assets": "^0.5.0",
|
|
63
63
|
"@utilitywarehouse/hearth-tokens": "^0.2.4"
|
|
64
64
|
},
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
CheckboxLabel,
|
|
10
10
|
CheckboxTile,
|
|
11
11
|
FormField,
|
|
12
|
+
Grid,
|
|
12
13
|
} from '../../';
|
|
13
14
|
import StorybookLink from '../../../../../shared/storybook/StorybookLink';
|
|
14
15
|
import { BackToTopButton, UsageWrap, ViewFigmaButton } from '../../../docs/components';
|
|
@@ -38,6 +39,7 @@ Whether you're building a simple form or a complex data collection system, the C
|
|
|
38
39
|
- [Variants](#variants)
|
|
39
40
|
- [Advanced Usage](#advanced-usage)
|
|
40
41
|
- [Examples](#examples)
|
|
42
|
+
- [Grid Layout With Tiles](#grid-layout-with-tiles)
|
|
41
43
|
- [`CheckboxTile` component](#checkboxtile-component)
|
|
42
44
|
- [`CheckboxImage` component](#checkboximage-component)
|
|
43
45
|
- [`CheckboxGroup` component](#checkboxgroup-component)
|
|
@@ -313,6 +315,44 @@ const MyComponent = () => {
|
|
|
313
315
|
|
|
314
316
|
## Examples
|
|
315
317
|
|
|
318
|
+
### Grid Layout With Tiles
|
|
319
|
+
|
|
320
|
+
Wrap tile checkboxes in a `Grid` when you want a multi-column layout inside a `CheckboxGroup`.
|
|
321
|
+
|
|
322
|
+
<UsageWrap>
|
|
323
|
+
<Center>
|
|
324
|
+
<Box minWidth={400}>
|
|
325
|
+
<CheckboxGroup label="Which options helped?" type="tile">
|
|
326
|
+
<Grid columns={2} spacing="md">
|
|
327
|
+
<Checkbox label="Fast response" value="fast-response" />
|
|
328
|
+
<Checkbox label="Clear steps" value="clear-steps" />
|
|
329
|
+
<Checkbox label="Useful example" value="useful-example" />
|
|
330
|
+
<Checkbox label="Still investigating" value="still-investigating" />
|
|
331
|
+
</Grid>
|
|
332
|
+
</CheckboxGroup>
|
|
333
|
+
</Box>
|
|
334
|
+
</Center>
|
|
335
|
+
</UsageWrap>
|
|
336
|
+
|
|
337
|
+
```tsx
|
|
338
|
+
import { Checkbox, CheckboxGroup, Grid } from '@utilitywarehouse/hearth-react-native';
|
|
339
|
+
|
|
340
|
+
const MyComponent = () => {
|
|
341
|
+
const [value, setValue] = React.useState(['fast-response']);
|
|
342
|
+
|
|
343
|
+
return (
|
|
344
|
+
<CheckboxGroup label="Which options helped?" type="tile" value={value} onChange={setValue}>
|
|
345
|
+
<Grid columns={2} spacing="md">
|
|
346
|
+
<Checkbox label="Fast response" value="fast-response" />
|
|
347
|
+
<Checkbox label="Clear steps" value="clear-steps" />
|
|
348
|
+
<Checkbox label="Useful example" value="useful-example" />
|
|
349
|
+
<Checkbox label="Still investigating" value="still-investigating" />
|
|
350
|
+
</Grid>
|
|
351
|
+
</CheckboxGroup>
|
|
352
|
+
);
|
|
353
|
+
};
|
|
354
|
+
```
|
|
355
|
+
|
|
316
356
|
### `CheckboxTile` component
|
|
317
357
|
|
|
318
358
|
The `CheckboxTile` component is a variant of the `Checkbox` component that displays the radio button as a card.
|
|
@@ -9,15 +9,14 @@ import { DetailText } from '../DetailText';
|
|
|
9
9
|
import { FormField, useFormFieldContext } from '../FormField';
|
|
10
10
|
import { Icon } from '../Icon';
|
|
11
11
|
import { Input } from '../Input';
|
|
12
|
+
import { SafeAreaView } from '../SafeAreaView';
|
|
12
13
|
import { Spinner } from '../Spinner';
|
|
13
14
|
import { UnstyledIconButton } from '../UnstyledIconButton';
|
|
14
|
-
import { ComboboxContext } from './Combobox.context';
|
|
15
|
-
import { ComboboxSelection } from './Combobox.context';
|
|
15
|
+
import { ComboboxContext, ComboboxSelection } from './Combobox.context';
|
|
16
16
|
import ComboboxProps, {
|
|
17
17
|
ComboboxOptionItemProps,
|
|
18
18
|
ComboboxRenderContentProps,
|
|
19
19
|
} from './Combobox.props';
|
|
20
|
-
import { SafeAreaView } from '../SafeAreaView';
|
|
21
20
|
import ComboboxOption from './ComboboxOption';
|
|
22
21
|
|
|
23
22
|
const DEFAULT_SNAP_POINTS = ['25%', '40%', '80%'];
|
|
@@ -376,9 +375,6 @@ const styles = StyleSheet.create(theme => ({
|
|
|
376
375
|
borderRadius: theme.components.input.borderRadius,
|
|
377
376
|
paddingHorizontal: theme.components.input.paddingHorizontal,
|
|
378
377
|
gap: theme.components.input.gap,
|
|
379
|
-
outlineStyle: 'solid',
|
|
380
|
-
outlineWidth: theme.components.input.borderWidth,
|
|
381
|
-
outlineColor: theme.color.border.strong,
|
|
382
378
|
variants: {
|
|
383
379
|
disabled: {
|
|
384
380
|
true: {
|
|
@@ -404,7 +400,9 @@ const styles = StyleSheet.create(theme => ({
|
|
|
404
400
|
},
|
|
405
401
|
},
|
|
406
402
|
triggerFocused: {
|
|
407
|
-
|
|
403
|
+
outlineStyle: 'solid',
|
|
404
|
+
outlineWidth: theme.components.input.borderWidth,
|
|
405
|
+
outlineColor: theme.color.border.strong,
|
|
408
406
|
},
|
|
409
407
|
leadingIconContainer: {
|
|
410
408
|
alignItems: 'center',
|
|
@@ -478,36 +478,57 @@ import { useCallback, useEffect, useRef } from 'react';
|
|
|
478
478
|
import { Platform, StyleSheet, View } from 'react-native';
|
|
479
479
|
|
|
480
480
|
import { BodyText, Heading, InlineLink, Modal } from '@utilitywarehouse/hearth-react-native';
|
|
481
|
+
import type { NavigationAction } from '@react-navigation/native';
|
|
481
482
|
|
|
482
|
-
export default function ModalScreen() {
|
|
483
|
+
export default function ModalScreen({ onClose }: { onClose?: () => void }) {
|
|
483
484
|
const modalRef = useRef<Modal>(null);
|
|
484
485
|
const navigation = useNavigation();
|
|
485
486
|
const isClosingRef = useRef(false);
|
|
486
487
|
|
|
487
|
-
const handleClose = useCallback(
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
// Trigger our custom animation first
|
|
496
|
-
modalRef.current?.triggerCloseAnimation?.();
|
|
488
|
+
const handleClose = useCallback(
|
|
489
|
+
(action?: NavigationAction) => {
|
|
490
|
+
if (Platform.OS === 'ios') {
|
|
491
|
+
if (onClose) {
|
|
492
|
+
onClose();
|
|
493
|
+
} else {
|
|
494
|
+
navigation.goBack();
|
|
495
|
+
}
|
|
497
496
|
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
497
|
+
return;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
if (isClosingRef.current) {
|
|
501
|
+
return;
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
isClosingRef.current = true;
|
|
505
|
+
// Trigger our custom animation first
|
|
506
|
+
modalRef.current?.triggerCloseAnimation?.();
|
|
507
|
+
|
|
508
|
+
// Delay the actual navigation to allow our animation to play
|
|
509
|
+
setTimeout(() => {
|
|
510
|
+
if (onClose) {
|
|
511
|
+
onClose();
|
|
512
|
+
} else if (action) {
|
|
513
|
+
// Dispatch the original action (e.g. popToTop, replace, reset)
|
|
514
|
+
// so we don't override the caller's intended navigation behaviour
|
|
515
|
+
navigation.dispatch(action);
|
|
516
|
+
} else {
|
|
517
|
+
navigation.goBack();
|
|
518
|
+
}
|
|
519
|
+
}, 100); // Match Modal animation duration
|
|
520
|
+
},
|
|
521
|
+
[navigation, onClose]
|
|
522
|
+
);
|
|
503
523
|
|
|
504
524
|
useEffect(() => {
|
|
505
525
|
if (Platform.OS === 'android') {
|
|
506
526
|
const unsubscribe = navigation.addListener('beforeRemove', e => {
|
|
507
527
|
if (!isClosingRef.current) {
|
|
508
|
-
// Prevent default behavior
|
|
528
|
+
// Prevent default behavior of the navigation action so we can
|
|
529
|
+
// play the close animation before letting navigation proceed
|
|
509
530
|
e.preventDefault();
|
|
510
|
-
handleClose();
|
|
531
|
+
handleClose(e.data.action);
|
|
511
532
|
}
|
|
512
533
|
});
|
|
513
534
|
|
|
@@ -3,6 +3,7 @@ import { TickSmallIcon } from '@utilitywarehouse/hearth-react-native-icons';
|
|
|
3
3
|
import {
|
|
4
4
|
Box,
|
|
5
5
|
Center,
|
|
6
|
+
Grid,
|
|
6
7
|
Radio,
|
|
7
8
|
RadioGroup,
|
|
8
9
|
RadioIcon,
|
|
@@ -41,6 +42,7 @@ The Radio component presents users with predefined choices and enables them to s
|
|
|
41
42
|
- [Variants](#variants)
|
|
42
43
|
- [Advanced Usage](#advanced-usage)
|
|
43
44
|
- [Examples](#examples)
|
|
45
|
+
- [Grid Layout With Tiles](#grid-layout-with-tiles)
|
|
44
46
|
- [`RadioTile` component](#radiotile-component)
|
|
45
47
|
- [`RadioImage` component](#radioimage-component)
|
|
46
48
|
- [`RadioGroup` component](#radiogroup-component)
|
|
@@ -238,6 +240,44 @@ const AdvancedExample = () => {
|
|
|
238
240
|
|
|
239
241
|
## Examples
|
|
240
242
|
|
|
243
|
+
### Grid Layout With Tiles
|
|
244
|
+
|
|
245
|
+
Wrap tile radios in a `Grid` when you want a multi-column layout while keeping the `RadioGroup` label, helper text and validation messaging.
|
|
246
|
+
|
|
247
|
+
<UsageWrap>
|
|
248
|
+
<Center>
|
|
249
|
+
<RadioGroup label="Did this solve your problem?" type="tile">
|
|
250
|
+
<Box minWidth={300}>
|
|
251
|
+
<Grid columns={2} spacing="md">
|
|
252
|
+
<Radio label="Yes" value="yes" />
|
|
253
|
+
<Radio label="No" value="no" />
|
|
254
|
+
<Radio label="Partly" value="partly" />
|
|
255
|
+
<Radio label="Not yet" value="not-yet" />
|
|
256
|
+
</Grid>
|
|
257
|
+
</Box>
|
|
258
|
+
</RadioGroup>
|
|
259
|
+
</Center>
|
|
260
|
+
</UsageWrap>
|
|
261
|
+
|
|
262
|
+
```tsx
|
|
263
|
+
import { Grid, Radio, RadioGroup } from '@utilitywarehouse/hearth-react-native';
|
|
264
|
+
|
|
265
|
+
const MyComponent = () => {
|
|
266
|
+
const [value, setValue] = React.useState('yes');
|
|
267
|
+
|
|
268
|
+
return (
|
|
269
|
+
<RadioGroup label="Did this solve your problem?" type="tile" value={value} onChange={setValue}>
|
|
270
|
+
<Grid columns={2} spacing="md">
|
|
271
|
+
<Radio label="Yes" value="yes" />
|
|
272
|
+
<Radio label="No" value="no" />
|
|
273
|
+
<Radio label="Partly" value="partly" />
|
|
274
|
+
<Radio label="Not yet" value="not-yet" />
|
|
275
|
+
</Grid>
|
|
276
|
+
</RadioGroup>
|
|
277
|
+
);
|
|
278
|
+
};
|
|
279
|
+
```
|
|
280
|
+
|
|
241
281
|
### `RadioTile` component
|
|
242
282
|
|
|
243
283
|
The `RadioTile` component is a variant of the `Radio` component that displays the radio button as a card.
|
|
@@ -203,13 +203,16 @@ const Select = ({
|
|
|
203
203
|
)}
|
|
204
204
|
|
|
205
205
|
{children ? (
|
|
206
|
-
<BottomSheetScrollView
|
|
206
|
+
<BottomSheetScrollView testID={testID ? `${testID}-options` : undefined}>
|
|
207
|
+
{children}
|
|
208
|
+
</BottomSheetScrollView>
|
|
207
209
|
) : (
|
|
208
210
|
<BottomSheetFlatList
|
|
209
211
|
data={filteredOptions}
|
|
210
212
|
keyExtractor={(option: any) => option.value}
|
|
211
213
|
renderItem={renderSelectOption}
|
|
212
214
|
ListEmptyComponent={renderEmptyComponent}
|
|
215
|
+
testID={testID ? `${testID}-options` : undefined}
|
|
213
216
|
{...listProps}
|
|
214
217
|
/>
|
|
215
218
|
)}
|