@utilitywarehouse/hearth-react-native 0.23.0-test-list → 0.24.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 +4 -5
- package/.turbo/turbo-lint.log +72 -0
- package/CHANGELOG.md +36 -0
- package/build/components/List/List.js +2 -2
- package/build/components/Modal/Modal.js +5 -4
- package/build/components/Modal/Modal.props.d.ts +10 -4
- package/build/components/index.d.ts +1 -0
- package/build/components/index.js +1 -0
- package/docs/components/AllComponents.web.tsx +6 -0
- package/package.json +2 -2
- package/src/components/List/List.tsx +4 -5
- package/src/components/Modal/Modal.props.ts +13 -4
- package/src/components/Modal/Modal.stories.tsx +1 -1
- package/src/components/Modal/Modal.tsx +28 -11
- package/src/components/ProgressBar/ProgressBar.docs.mdx +90 -0
- package/src/components/ProgressBar/ProgressBar.figma.tsx +79 -0
- package/src/components/ProgressBar/ProgressBar.props.ts +60 -0
- package/src/components/ProgressBar/ProgressBar.stories.tsx +117 -0
- package/src/components/ProgressBar/ProgressBar.tsx +74 -0
- package/src/components/ProgressBar/ProgressBarCircular.tsx +181 -0
- package/src/components/ProgressBar/ProgressBarLinear.tsx +127 -0
- package/src/components/ProgressBar/index.ts +7 -0
- package/src/components/index.ts +1 -0
- package/build/components/SegmentedControl/SegmentedControl.context.d.ts +0 -14
- package/build/components/SegmentedControl/SegmentedControl.context.js +0 -9
- package/build/components/SegmentedControl/SegmentedControl.d.ts +0 -6
- package/build/components/SegmentedControl/SegmentedControl.js +0 -199
- package/build/components/SegmentedControl/SegmentedControl.props.d.ts +0 -18
- package/build/components/SegmentedControl/SegmentedControl.props.js +0 -1
- package/build/components/SegmentedControl/SegmentedControlOption.d.ts +0 -18
- package/build/components/SegmentedControl/SegmentedControlOption.js +0 -144
- package/build/components/SegmentedControl/SegmentedControlOption.props.d.ts +0 -14
- package/build/components/SegmentedControl/SegmentedControlOption.props.js +0 -1
- package/build/components/SegmentedControl/index.d.ts +0 -4
- package/build/components/SegmentedControl/index.js +0 -2
- package/build/components/TimePicker/TimePicker.d.ts +0 -6
- package/build/components/TimePicker/TimePicker.js +0 -78
- package/build/components/TimePicker/TimePicker.props.d.ts +0 -45
- package/build/components/TimePicker/TimePicker.props.js +0 -1
- package/build/components/TimePicker/TimePickerView.d.ts +0 -12
- package/build/components/TimePicker/TimePickerView.js +0 -130
- package/build/components/TimePicker/TimePickerWheel.d.ts +0 -8
- package/build/components/TimePicker/TimePickerWheel.js +0 -86
- package/build/components/TimePicker/TimePickerWheel.web.d.ts +0 -8
- package/build/components/TimePicker/TimePickerWheel.web.js +0 -122
- package/build/components/TimePicker/index.d.ts +0 -6
- package/build/components/TimePicker/index.js +0 -3
- package/build/components/TimePickerInput/TimePickerInput.d.ts +0 -6
- package/build/components/TimePickerInput/TimePickerInput.js +0 -127
- package/build/components/TimePickerInput/TimePickerInput.props.d.ts +0 -52
- package/build/components/TimePickerInput/TimePickerInput.props.js +0 -1
- package/build/components/TimePickerInput/TimePickerInputDoneButton.d.ts +0 -8
- package/build/components/TimePickerInput/TimePickerInputDoneButton.js +0 -19
- package/build/components/TimePickerInput/TimePickerInputDoneButton.web.d.ts +0 -5
- package/build/components/TimePickerInput/TimePickerInputDoneButton.web.js +0 -5
- package/build/components/TimePickerInput/index.d.ts +0 -2
- package/build/components/TimePickerInput/index.js +0 -1
- package/build/components/VerificationInput/VerificationInput.utils.d.ts +0 -8
- package/build/components/VerificationInput/VerificationInput.utils.js +0 -17
- package/build/components/VerificationInput/VerificationInput.utils.test.d.ts +0 -1
- package/build/components/VerificationInput/VerificationInput.utils.test.js +0 -36
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
>
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
|
|
2
|
+
> @utilitywarehouse/hearth-react-native@0.24.0 build /home/runner/work/hearth/hearth/packages/react-native
|
|
3
|
+
> tsc
|
|
4
|
+
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
|
|
2
|
+
> @utilitywarehouse/hearth-react-native@0.24.0 lint /home/runner/work/hearth/hearth/packages/react-native
|
|
3
|
+
> TIMING=1 eslint .
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
/home/runner/work/hearth/hearth/packages/react-native/src/components/Carousel/Carousel.context.tsx
|
|
7
|
+
6:14 warning Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components react-refresh/only-export-components
|
|
8
|
+
|
|
9
|
+
/home/runner/work/hearth/hearth/packages/react-native/src/components/Carousel/Carousel.tsx
|
|
10
|
+
146:6 warning React Hook useMemo has a missing dependency: 'hasCarouselControlsInTree'. Either include it or remove the dependency array react-hooks/exhaustive-deps
|
|
11
|
+
|
|
12
|
+
/home/runner/work/hearth/hearth/packages/react-native/src/components/DatePicker/DatePicker.tsx
|
|
13
|
+
109:6 warning React Hook useCallback has an unnecessary dependency: 'modalRef.current'. Either exclude it or remove the dependency array. Mutable values like 'modalRef.current' aren't valid dependencies because mutating them doesn't re-render the component react-hooks/exhaustive-deps
|
|
14
|
+
259:6 warning React Hook useEffect has a missing dependency: 'initialState'. Either include it or remove the dependency array react-hooks/exhaustive-deps
|
|
15
|
+
346:6 warning React Hook useEffect has a missing dependency: 'onChange'. Either include it or remove the dependency array react-hooks/exhaustive-deps
|
|
16
|
+
468:5 warning React Hook useCallback has a missing dependency: 'onChange'. Either include it or remove the dependency array react-hooks/exhaustive-deps
|
|
17
|
+
536:6 warning React Hook useEffect has a missing dependency: 'onSelectMonth'. Either include it or remove the dependency array react-hooks/exhaustive-deps
|
|
18
|
+
542:6 warning React Hook useEffect has a missing dependency: 'onSelectYear'. Either include it or remove the dependency array react-hooks/exhaustive-deps
|
|
19
|
+
|
|
20
|
+
/home/runner/work/hearth/hearth/packages/react-native/src/components/DatePicker/DatePickerDay.tsx
|
|
21
|
+
76:6 warning React Hook useMemo has an unnecessary dependency: 'styles.rangeRoot'. Either exclude it or remove the dependency array. Outer scope values like 'styles.rangeRoot' aren't valid dependencies because mutating them doesn't re-render the component react-hooks/exhaustive-deps
|
|
22
|
+
84:6 warning React Hook useMemo has a missing dependency: 'isSelected'. Either include it or remove the dependency array react-hooks/exhaustive-deps
|
|
23
|
+
|
|
24
|
+
/home/runner/work/hearth/hearth/packages/react-native/src/components/DatePicker/DatePickerDays.tsx
|
|
25
|
+
179:6 warning React Hook useMemo has unnecessary dependencies: 'month' and 'year'. Either exclude them or remove the dependency array react-hooks/exhaustive-deps
|
|
26
|
+
|
|
27
|
+
/home/runner/work/hearth/hearth/packages/react-native/src/components/DatePicker/DatePickerYears.tsx
|
|
28
|
+
52:6 warning React Hook useCallback has a missing dependency: 'containerHeight'. Either include it or remove the dependency array. Outer scope values like 'styles' aren't valid dependencies because mutating them doesn't re-render the component react-hooks/exhaustive-deps
|
|
29
|
+
|
|
30
|
+
/home/runner/work/hearth/hearth/packages/react-native/src/components/Input/Input.tsx
|
|
31
|
+
78:8 warning React Hook useEffect has a missing dependency: 'formFieldContext'. Either include it or remove the dependency array react-hooks/exhaustive-deps
|
|
32
|
+
|
|
33
|
+
/home/runner/work/hearth/hearth/packages/react-native/src/components/Modal/Modal.tsx
|
|
34
|
+
75:6 warning React Hook useCallback has an unnecessary dependency: 'Platform.OS'. Either exclude it or remove the dependency array. Outer scope values like 'Platform.OS' aren't valid dependencies because mutating them doesn't re-render the component react-hooks/exhaustive-deps
|
|
35
|
+
291:5 warning React Hook useCallback has a missing dependency: 'footer'. Either include it or remove the dependency array react-hooks/exhaustive-deps
|
|
36
|
+
|
|
37
|
+
/home/runner/work/hearth/hearth/packages/react-native/src/components/Modal/Modal.web.tsx
|
|
38
|
+
66:6 warning React Hook useCallback has an unnecessary dependency: 'Platform.OS'. Either exclude it or remove the dependency array. Outer scope values like 'Platform.OS' aren't valid dependencies because mutating them doesn't re-render the component react-hooks/exhaustive-deps
|
|
39
|
+
|
|
40
|
+
/home/runner/work/hearth/hearth/packages/react-native/src/components/PillGroup/PillGroup.tsx
|
|
41
|
+
17:9 warning The 'normalizedValue' conditional could make the dependencies of useMemo Hook (at line 33) change on every render. Move it inside the useMemo callback. Alternatively, wrap the initialization of 'normalizedValue' in its own useMemo() Hook react-hooks/exhaustive-deps
|
|
42
|
+
|
|
43
|
+
/home/runner/work/hearth/hearth/packages/react-native/src/components/Tabs/Tabs.tsx
|
|
44
|
+
53:6 warning React Hook useEffect has a missing dependency: 'tabValues'. Either include it or remove the dependency array react-hooks/exhaustive-deps
|
|
45
|
+
53:7 warning React Hook useEffect has a complex expression in the dependency array. Extract it to a separate variable so it can be statically checked react-hooks/exhaustive-deps
|
|
46
|
+
104:5 warning React Hook useMemo has an unnecessary dependency: 'tabValues'. Either exclude it or remove the dependency array react-hooks/exhaustive-deps
|
|
47
|
+
127:62 warning React Hook useEffect has a complex expression in the dependency array. Extract it to a separate variable so it can be statically checked react-hooks/exhaustive-deps
|
|
48
|
+
|
|
49
|
+
/home/runner/work/hearth/hearth/packages/react-native/src/components/Textarea/Textarea.tsx
|
|
50
|
+
45:6 warning React Hook useEffect has a missing dependency: 'formFieldContext'. Either include it or remove the dependency array react-hooks/exhaustive-deps
|
|
51
|
+
|
|
52
|
+
/home/runner/work/hearth/hearth/packages/react-native/src/components/Toast/Toast.context.tsx
|
|
53
|
+
14:14 warning Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components react-refresh/only-export-components
|
|
54
|
+
106:14 warning Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components react-refresh/only-export-components
|
|
55
|
+
|
|
56
|
+
/home/runner/work/hearth/hearth/packages/react-native/src/components/VerificationInput/VerificationInput.tsx
|
|
57
|
+
174:7 warning React Hook useImperativeHandle has a missing dependency: 'updateValue'. Either include it or remove the dependency array react-hooks/exhaustive-deps
|
|
58
|
+
|
|
59
|
+
✖ 25 problems (0 errors, 25 warnings)
|
|
60
|
+
|
|
61
|
+
Rule | Time (ms) | Relative
|
|
62
|
+
:-----------------------------------------|----------:|--------:
|
|
63
|
+
@typescript-eslint/no-unused-vars | 1400.036 | 60.2%
|
|
64
|
+
react-hooks/exhaustive-deps | 100.065 | 4.3%
|
|
65
|
+
react-hooks/rules-of-hooks | 83.204 | 3.6%
|
|
66
|
+
no-global-assign | 71.807 | 3.1%
|
|
67
|
+
@typescript-eslint/ban-ts-comment | 53.514 | 2.3%
|
|
68
|
+
no-loss-of-precision | 35.722 | 1.5%
|
|
69
|
+
@typescript-eslint/triple-slash-reference | 35.355 | 1.5%
|
|
70
|
+
no-unexpected-multiline | 32.651 | 1.4%
|
|
71
|
+
no-useless-escape | 30.776 | 1.3%
|
|
72
|
+
no-misleading-character-class | 29.528 | 1.3%
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,41 @@
|
|
|
1
1
|
# @utilitywarehouse/hearth-react-native
|
|
2
2
|
|
|
3
|
+
## 0.24.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#977](https://github.com/utilitywarehouse/hearth/pull/977) [`9d2b534`](https://github.com/utilitywarehouse/hearth/commit/9d2b5348a5748cb613f537808069de2e86bd21d7) Thanks [@jordmccord](https://github.com/jordmccord)! - 🌟 [FEATURE]: Add `ProgressBar` component with linear and circular variants.
|
|
8
|
+
|
|
9
|
+
**Developer changes**:
|
|
10
|
+
|
|
11
|
+
Use `ProgressBar` with a default percentage label, or override the label to show a custom value:
|
|
12
|
+
|
|
13
|
+
```tsx
|
|
14
|
+
import { ProgressBar } from '@utilitywarehouse/hearth-react-native';
|
|
15
|
+
|
|
16
|
+
<ProgressBar value={42} label="Uploading documents" />
|
|
17
|
+
|
|
18
|
+
<ProgressBar
|
|
19
|
+
value={68}
|
|
20
|
+
max={100}
|
|
21
|
+
label="Data allowance"
|
|
22
|
+
variant="circular"
|
|
23
|
+
formatValueText={(value, { max }) => `${max - value}GB remaining`}
|
|
24
|
+
/>
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### Patch Changes
|
|
28
|
+
|
|
29
|
+
- [#978](https://github.com/utilitywarehouse/hearth/pull/978) [`26a1173`](https://github.com/utilitywarehouse/hearth/commit/26a11731a493a8b92ac2a3a183516376ab54663b) Thanks [@jordmccord](https://github.com/jordmccord)! - 💅 [ENHANCEMENT]: Tighten `Modal` prop types and fix brand background text styling
|
|
30
|
+
|
|
31
|
+
Improves TypeScript safety so `stickyFooter` is not allowed when `inNavModal` is true, and `background` can only be set when `inNavModal` is true. Also ensures headings, body text, and button content are correctly inverted when using the brand background.
|
|
32
|
+
|
|
33
|
+
**Components affected**:
|
|
34
|
+
- `Modal`
|
|
35
|
+
|
|
36
|
+
**Developer changes**:
|
|
37
|
+
No changes required unless you were relying on invalid prop combinations.
|
|
38
|
+
|
|
3
39
|
## 0.23.0
|
|
4
40
|
|
|
5
41
|
### Minor Changes
|
|
@@ -6,7 +6,7 @@ import { Card } from '../Card';
|
|
|
6
6
|
import { SectionHeader } from '../SectionHeader';
|
|
7
7
|
import { ListContext } from './List.context';
|
|
8
8
|
const List = ({ children, heading, helperText, headerTrailingContent, invalidText, ...props }) => {
|
|
9
|
-
const { loading, disabled, container = 'none'
|
|
9
|
+
const { loading, disabled, container = 'none' } = props;
|
|
10
10
|
const orderRef = useRef([]);
|
|
11
11
|
const [firstItemId, setFirstItemId] = useState(undefined);
|
|
12
12
|
const containerToCard = {
|
|
@@ -35,7 +35,7 @@ const List = ({ children, heading, helperText, headerTrailingContent, invalidTex
|
|
|
35
35
|
registerItem,
|
|
36
36
|
};
|
|
37
37
|
styles.useVariants({ disabled });
|
|
38
|
-
return (_jsx(ListContext.Provider, { value: value, children: _jsxs(View, { ...
|
|
38
|
+
return (_jsx(ListContext.Provider, { value: value, children: _jsxs(View, { ...props, style: [styles.container, props.style], children: [heading ? (_jsx(SectionHeader, { heading: heading, helperText: helperText, trailingContent: headerTrailingContent, invalidText: invalidText })) : null, container === 'none' ? (_jsx(View, { children: children })) : (React.Children.count(children) > 0 && (_jsx(Card, { ...containerToCard, noPadding: true, style: styles.card, children: _jsx(_Fragment, { children: children }) })))] }) }));
|
|
39
39
|
};
|
|
40
40
|
List.displayName = 'List';
|
|
41
41
|
const styles = StyleSheet.create(theme => ({
|
|
@@ -20,6 +20,7 @@ const Modal = ({ ref, children, heading, description, showCloseButton = true, pr
|
|
|
20
20
|
const theme = useTheme();
|
|
21
21
|
const backgroundOpacity = useSharedValue(0);
|
|
22
22
|
const pretendContentTranslateY = useSharedValue(20);
|
|
23
|
+
const isBrandBackground = background === 'brand';
|
|
23
24
|
const triggerCloseAnimation = useCallback(() => {
|
|
24
25
|
if (Platform.OS === 'android' && inNavModal) {
|
|
25
26
|
pretendContentTranslateY.value = withTiming(20, {
|
|
@@ -105,10 +106,10 @@ const Modal = ({ ref, children, heading, description, showCloseButton = true, pr
|
|
|
105
106
|
noButtons,
|
|
106
107
|
stickyFooter,
|
|
107
108
|
showHandle: props.showHandle,
|
|
108
|
-
background:
|
|
109
|
+
background: isBrandBackground ? 'brand' : 'primary',
|
|
109
110
|
});
|
|
110
|
-
const footer = (_jsxs(View, { style: styles.footer, children: [onPressPrimaryButton && primaryButtonText ? (_jsx(Button, { onPress: handlePrimaryButtonPress, text: primaryButtonText, inverted:
|
|
111
|
-
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, ref: viewRef, children: [_jsx(Spinner, { size: "lg" }), _jsx(Heading, { size: "lg", textAlign: "center", children: loadingHeading })] })) : (_jsxs(View, { style: styles.container, accessible: Platform.OS === 'android' ? true : undefined, accessibilityLabel: Platform.OS === 'android' ? 'Modal content' : undefined, screenReaderFocusable: true, ref: viewRef, children: [_jsxs(View, { style: styles.header, children: [_jsxs(View, { style: styles.headerTextContent, children: [heading && !image ? (_jsx(Heading, { size: "lg", accessible: true, children: heading })) : null, description && !image ? _jsx(BodyText, { accessible: true, children: description }) : null] }), showCloseButton ? (_jsx(UnstyledIconButton, { icon: CloseMediumIcon, onPress: handleCloseButtonPress, accessibilityLabel: "Close modal", inverted:
|
|
111
|
+
const footer = (_jsxs(View, { style: styles.footer, children: [onPressPrimaryButton && primaryButtonText ? (_jsx(Button, { onPress: handlePrimaryButtonPress, text: primaryButtonText, inverted: isBrandBackground && inNavModal, ...primaryButtonProps, variant: primaryButtonProps?.variant ?? 'solid', colorScheme: primaryButtonProps?.colorScheme ?? 'highlight' })) : null, onPressSecondaryButton && secondaryButtonText ? (_jsx(Button, { onPress: handleSecondaryButtonPress, text: secondaryButtonText, inverted: isBrandBackground && inNavModal, ...secondaryButtonProps, variant: secondaryButtonProps?.variant ?? 'outline', colorScheme: secondaryButtonProps?.colorScheme ?? 'functional' })) : null] }));
|
|
112
|
+
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, ref: viewRef, children: [_jsx(Spinner, { size: "lg", color: isBrandBackground && inNavModal ? theme.color.icon.inverted : undefined }), _jsx(Heading, { size: "lg", textAlign: "center", inverted: isBrandBackground && inNavModal, children: loadingHeading })] })) : (_jsxs(View, { style: styles.container, accessible: Platform.OS === 'android' ? true : undefined, accessibilityLabel: Platform.OS === 'android' ? 'Modal content' : undefined, screenReaderFocusable: true, ref: viewRef, children: [_jsxs(View, { style: styles.header, children: [_jsxs(View, { style: styles.headerTextContent, children: [heading && !image ? (_jsx(Heading, { size: "lg", accessible: true, inverted: isBrandBackground && inNavModal, children: heading })) : null, description && !image ? (_jsx(BodyText, { accessible: true, inverted: isBrandBackground && inNavModal, children: description })) : null] }), showCloseButton ? (_jsx(UnstyledIconButton, { icon: CloseMediumIcon, onPress: handleCloseButtonPress, accessibilityLabel: "Close modal", inverted: isBrandBackground && inNavModal, ...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 && inNavModal, children: heading })) : null, description ? (_jsx(BodyText, { textAlign: "center", accessible: true, inverted: isBrandBackground && inNavModal, children: description })) : null] })] })) : null, inNavModal ? _jsx(ScrollView, { style: { flex: 1 }, children: children }) : children, (!stickyFooter || inNavModal) && !noButtons ? footer : null] })) }));
|
|
112
113
|
const renderFooter = useCallback((props) => (_jsx(BottomSheetFooter, { ...props, children: _jsx(View, { style: styles.footerWrap, children: footer }) })), [
|
|
113
114
|
onPressPrimaryButton,
|
|
114
115
|
primaryButtonText,
|
|
@@ -119,7 +120,7 @@ const Modal = ({ ref, children, heading, description, showCloseButton = true, pr
|
|
|
119
120
|
]);
|
|
120
121
|
return inNavModal ? (_jsxs(View, { style: {
|
|
121
122
|
flex: 1,
|
|
122
|
-
backgroundColor: theme.color.background[
|
|
123
|
+
backgroundColor: theme.color.background[isBrandBackground ? 'brand' : 'primary'],
|
|
123
124
|
}, children: [Platform.OS === 'android' ? (_jsx(Animated.View, { style: [styles.androidContainer, animatedBackgroundStyle], children: _jsx(Animated.View, { style: [styles.pretendContent, animatedPretendContentStyle] }) })) : null, _jsx(Animated.View, { style: [styles.inNavModalContainer, Platform.OS === 'android' && animatedInNavModalStyle], children: _jsx(View, { style: styles.inNavModalContent, children: content }) })] })) : (_jsxs(BottomSheetModal, { ref: bottomSheetModalRef, enableDynamicSizing: true, snapPoints: image || fullscreen ? ['90%'] : props.snapPoints, showHandle: typeof loading !== 'undefined' && loading ? false : props.showHandle, accessible: false, style: styles.modal, footerComponent: stickyFooter && !noButtons ? renderFooter : undefined, ...props, onChange: handleChange, children: [loading ? _jsx(View, { style: styles.loadingTop }) : null, _jsx(BottomSheetScrollView, { contentContainerStyle: styles.scrollView, ref: scrollViewRef, children: content })] }));
|
|
124
125
|
};
|
|
125
126
|
const styles = StyleSheet.create((theme, rt) => ({
|
|
@@ -3,16 +3,14 @@ import { ViewProps } from 'react-native';
|
|
|
3
3
|
import { BottomSheetProps } from '../BottomSheet';
|
|
4
4
|
import { ButtonWithoutChildrenProps } from '../Button/Button.props';
|
|
5
5
|
import { UnstyledIconButtonProps } from '../UnstyledIconButton';
|
|
6
|
-
interface
|
|
6
|
+
interface ModalPropsBase extends Omit<BottomSheetProps, 'children'> {
|
|
7
7
|
loading?: boolean;
|
|
8
8
|
image?: ReactNode;
|
|
9
9
|
showCloseButton?: boolean;
|
|
10
10
|
heading?: string;
|
|
11
11
|
loadingHeading?: string;
|
|
12
12
|
description?: string;
|
|
13
|
-
inNavModal?: boolean;
|
|
14
13
|
fullscreen?: boolean;
|
|
15
|
-
stickyFooter?: boolean;
|
|
16
14
|
children?: ViewProps['children'];
|
|
17
15
|
onPressPrimaryButton?: () => void;
|
|
18
16
|
primaryButtonText?: string;
|
|
@@ -24,6 +22,14 @@ interface ModalProps extends Omit<BottomSheetProps, 'children'> {
|
|
|
24
22
|
primaryButtonProps?: Omit<ButtonWithoutChildrenProps, 'children'>;
|
|
25
23
|
secondaryButtonProps?: Omit<ButtonWithoutChildrenProps, 'children'>;
|
|
26
24
|
closeButtonProps?: Omit<UnstyledIconButtonProps, 'children'>;
|
|
27
|
-
background?: 'default' | 'brand';
|
|
28
25
|
}
|
|
26
|
+
type ModalProps = (ModalPropsBase & {
|
|
27
|
+
inNavModal?: false | undefined;
|
|
28
|
+
stickyFooter?: boolean;
|
|
29
|
+
background?: never;
|
|
30
|
+
}) | (ModalPropsBase & {
|
|
31
|
+
inNavModal: true;
|
|
32
|
+
stickyFooter?: never;
|
|
33
|
+
background?: 'default' | 'brand';
|
|
34
|
+
});
|
|
29
35
|
export default ModalProps;
|
|
@@ -74,6 +74,7 @@ import {
|
|
|
74
74
|
OL,
|
|
75
75
|
Pill,
|
|
76
76
|
PillGroup,
|
|
77
|
+
ProgressBar,
|
|
77
78
|
ProgressStep,
|
|
78
79
|
ProgressStepper,
|
|
79
80
|
Radio,
|
|
@@ -663,6 +664,11 @@ const AllComponents: React.FC = () => {
|
|
|
663
664
|
</PillGroup>
|
|
664
665
|
</Center>
|
|
665
666
|
</ComponentWrapper>
|
|
667
|
+
<ComponentWrapper name="Progress Bar" link="/?path=/docs/components-progress-bar--docs">
|
|
668
|
+
<Center flex={1} px="300">
|
|
669
|
+
<ProgressBar value={58} label="Order progress" />
|
|
670
|
+
</Center>
|
|
671
|
+
</ComponentWrapper>
|
|
666
672
|
<ComponentWrapper
|
|
667
673
|
name="Progress Stepper"
|
|
668
674
|
link="/?path=/docs/components-progress-stepper--docs"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@utilitywarehouse/hearth-react-native",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.24.0",
|
|
4
4
|
"description": "Utility Warehouse React Native UI library",
|
|
5
5
|
"main": "build/index.js",
|
|
6
6
|
"types": "build/index.d.ts",
|
|
@@ -55,9 +55,9 @@
|
|
|
55
55
|
"vite": "^7.1.3",
|
|
56
56
|
"vite-plugin-svgr": "^4.5.0",
|
|
57
57
|
"vitest": "^3.2.4",
|
|
58
|
-
"@utilitywarehouse/hearth-react-native-icons": "^0.8.0",
|
|
59
58
|
"@utilitywarehouse/hearth-fonts": "^0.0.4",
|
|
60
59
|
"@utilitywarehouse/hearth-react-icons": "^0.8.0",
|
|
60
|
+
"@utilitywarehouse/hearth-react-native-icons": "^0.8.0",
|
|
61
61
|
"@utilitywarehouse/hearth-svg-assets": "^0.5.0",
|
|
62
62
|
"@utilitywarehouse/hearth-tokens": "^0.2.3"
|
|
63
63
|
},
|
|
@@ -14,8 +14,7 @@ const List = ({
|
|
|
14
14
|
invalidText,
|
|
15
15
|
...props
|
|
16
16
|
}: ListProps) => {
|
|
17
|
-
const { loading, disabled, container = 'none'
|
|
18
|
-
|
|
17
|
+
const { loading, disabled, container = 'none' } = props;
|
|
19
18
|
const orderRef = useRef<string[]>([]);
|
|
20
19
|
const [firstItemId, setFirstItemId] = useState<string | undefined>(undefined);
|
|
21
20
|
const containerToCard: {
|
|
@@ -52,7 +51,7 @@ const List = ({
|
|
|
52
51
|
styles.useVariants({ disabled });
|
|
53
52
|
return (
|
|
54
53
|
<ListContext.Provider value={value}>
|
|
55
|
-
<View {...
|
|
54
|
+
<View {...props} style={[styles.container, props.style]}>
|
|
56
55
|
{heading ? (
|
|
57
56
|
<SectionHeader
|
|
58
57
|
heading={heading}
|
|
@@ -62,10 +61,10 @@ const List = ({
|
|
|
62
61
|
/>
|
|
63
62
|
) : null}
|
|
64
63
|
{container === 'none' ? (
|
|
65
|
-
<View
|
|
64
|
+
<View>{children}</View>
|
|
66
65
|
) : (
|
|
67
66
|
React.Children.count(children) > 0 && (
|
|
68
|
-
<Card {...containerToCard} noPadding style={styles.card}
|
|
67
|
+
<Card {...containerToCard} noPadding style={styles.card}>
|
|
69
68
|
<>{children}</>
|
|
70
69
|
</Card>
|
|
71
70
|
)
|
|
@@ -4,16 +4,14 @@ import { BottomSheetProps } from '../BottomSheet';
|
|
|
4
4
|
import { ButtonWithoutChildrenProps } from '../Button/Button.props';
|
|
5
5
|
import { UnstyledIconButtonProps } from '../UnstyledIconButton';
|
|
6
6
|
|
|
7
|
-
interface
|
|
7
|
+
interface ModalPropsBase extends Omit<BottomSheetProps, 'children'> {
|
|
8
8
|
loading?: boolean;
|
|
9
9
|
image?: ReactNode;
|
|
10
10
|
showCloseButton?: boolean;
|
|
11
11
|
heading?: string;
|
|
12
12
|
loadingHeading?: string;
|
|
13
13
|
description?: string;
|
|
14
|
-
inNavModal?: boolean;
|
|
15
14
|
fullscreen?: boolean;
|
|
16
|
-
stickyFooter?: boolean;
|
|
17
15
|
children?: ViewProps['children'];
|
|
18
16
|
onPressPrimaryButton?: () => void;
|
|
19
17
|
primaryButtonText?: string;
|
|
@@ -25,7 +23,18 @@ interface ModalProps extends Omit<BottomSheetProps, 'children'> {
|
|
|
25
23
|
primaryButtonProps?: Omit<ButtonWithoutChildrenProps, 'children'>;
|
|
26
24
|
secondaryButtonProps?: Omit<ButtonWithoutChildrenProps, 'children'>;
|
|
27
25
|
closeButtonProps?: Omit<UnstyledIconButtonProps, 'children'>;
|
|
28
|
-
background?: 'default' | 'brand';
|
|
29
26
|
}
|
|
30
27
|
|
|
28
|
+
type ModalProps =
|
|
29
|
+
| (ModalPropsBase & {
|
|
30
|
+
inNavModal?: false | undefined;
|
|
31
|
+
stickyFooter?: boolean;
|
|
32
|
+
background?: never;
|
|
33
|
+
})
|
|
34
|
+
| (ModalPropsBase & {
|
|
35
|
+
inNavModal: true;
|
|
36
|
+
stickyFooter?: never;
|
|
37
|
+
background?: 'default' | 'brand';
|
|
38
|
+
});
|
|
39
|
+
|
|
31
40
|
export default ModalProps;
|
|
@@ -59,6 +59,7 @@ const Modal = ({
|
|
|
59
59
|
const theme = useTheme();
|
|
60
60
|
const backgroundOpacity = useSharedValue(0);
|
|
61
61
|
const pretendContentTranslateY = useSharedValue(20);
|
|
62
|
+
const isBrandBackground = background === 'brand';
|
|
62
63
|
|
|
63
64
|
const triggerCloseAnimation = useCallback(() => {
|
|
64
65
|
if (Platform.OS === 'android' && inNavModal) {
|
|
@@ -171,7 +172,7 @@ const Modal = ({
|
|
|
171
172
|
noButtons,
|
|
172
173
|
stickyFooter,
|
|
173
174
|
showHandle: props.showHandle,
|
|
174
|
-
background:
|
|
175
|
+
background: isBrandBackground ? 'brand' : 'primary',
|
|
175
176
|
});
|
|
176
177
|
|
|
177
178
|
const footer = (
|
|
@@ -180,7 +181,7 @@ const Modal = ({
|
|
|
180
181
|
<Button
|
|
181
182
|
onPress={handlePrimaryButtonPress}
|
|
182
183
|
text={primaryButtonText}
|
|
183
|
-
inverted={
|
|
184
|
+
inverted={isBrandBackground && inNavModal}
|
|
184
185
|
{...primaryButtonProps}
|
|
185
186
|
variant={(primaryButtonProps?.variant as 'solid') ?? 'solid'}
|
|
186
187
|
colorScheme={(primaryButtonProps?.colorScheme as 'highlight') ?? 'highlight'}
|
|
@@ -190,7 +191,7 @@ const Modal = ({
|
|
|
190
191
|
<Button
|
|
191
192
|
onPress={handleSecondaryButtonPress}
|
|
192
193
|
text={secondaryButtonText}
|
|
193
|
-
inverted={
|
|
194
|
+
inverted={isBrandBackground && inNavModal}
|
|
194
195
|
{...secondaryButtonProps}
|
|
195
196
|
variant={(secondaryButtonProps?.variant as 'outline') ?? 'outline'}
|
|
196
197
|
colorScheme={(secondaryButtonProps?.colorScheme as 'functional') ?? 'functional'}
|
|
@@ -209,8 +210,11 @@ const Modal = ({
|
|
|
209
210
|
screenReaderFocusable
|
|
210
211
|
ref={viewRef}
|
|
211
212
|
>
|
|
212
|
-
<Spinner
|
|
213
|
-
|
|
213
|
+
<Spinner
|
|
214
|
+
size="lg"
|
|
215
|
+
color={isBrandBackground && inNavModal ? theme.color.icon.inverted : undefined}
|
|
216
|
+
/>
|
|
217
|
+
<Heading size="lg" textAlign="center" inverted={isBrandBackground && inNavModal}>
|
|
214
218
|
{loadingHeading}
|
|
215
219
|
</Heading>
|
|
216
220
|
</View>
|
|
@@ -225,18 +229,22 @@ const Modal = ({
|
|
|
225
229
|
<View style={styles.header}>
|
|
226
230
|
<View style={styles.headerTextContent}>
|
|
227
231
|
{heading && !image ? (
|
|
228
|
-
<Heading size="lg" accessible>
|
|
232
|
+
<Heading size="lg" accessible inverted={isBrandBackground && inNavModal}>
|
|
229
233
|
{heading}
|
|
230
234
|
</Heading>
|
|
231
235
|
) : null}
|
|
232
|
-
{description && !image ?
|
|
236
|
+
{description && !image ? (
|
|
237
|
+
<BodyText accessible inverted={isBrandBackground && inNavModal}>
|
|
238
|
+
{description}
|
|
239
|
+
</BodyText>
|
|
240
|
+
) : null}
|
|
233
241
|
</View>
|
|
234
242
|
{showCloseButton ? (
|
|
235
243
|
<UnstyledIconButton
|
|
236
244
|
icon={CloseMediumIcon}
|
|
237
245
|
onPress={handleCloseButtonPress}
|
|
238
246
|
accessibilityLabel="Close modal"
|
|
239
|
-
inverted={
|
|
247
|
+
inverted={isBrandBackground && inNavModal}
|
|
240
248
|
{...closeButtonProps}
|
|
241
249
|
/>
|
|
242
250
|
) : null}
|
|
@@ -246,12 +254,21 @@ const Modal = ({
|
|
|
246
254
|
{image}
|
|
247
255
|
<View style={styles.textContent}>
|
|
248
256
|
{heading ? (
|
|
249
|
-
<Heading
|
|
257
|
+
<Heading
|
|
258
|
+
size="lg"
|
|
259
|
+
textAlign="center"
|
|
260
|
+
accessible
|
|
261
|
+
inverted={isBrandBackground && inNavModal}
|
|
262
|
+
>
|
|
250
263
|
{heading}
|
|
251
264
|
</Heading>
|
|
252
265
|
) : null}
|
|
253
266
|
{description ? (
|
|
254
|
-
<BodyText
|
|
267
|
+
<BodyText
|
|
268
|
+
textAlign="center"
|
|
269
|
+
accessible
|
|
270
|
+
inverted={isBrandBackground && inNavModal}
|
|
271
|
+
>
|
|
255
272
|
{description}
|
|
256
273
|
</BodyText>
|
|
257
274
|
) : null}
|
|
@@ -285,7 +302,7 @@ const Modal = ({
|
|
|
285
302
|
<View
|
|
286
303
|
style={{
|
|
287
304
|
flex: 1,
|
|
288
|
-
backgroundColor: theme.color.background[
|
|
305
|
+
backgroundColor: theme.color.background[isBrandBackground ? 'brand' : 'primary'],
|
|
289
306
|
}}
|
|
290
307
|
>
|
|
291
308
|
{Platform.OS === 'android' ? (
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { Canvas, Controls, Meta } from '@storybook/addon-docs/blocks';
|
|
2
|
+
import { Box, Center, ProgressBar } from '../..';
|
|
3
|
+
import { BackToTopButton, UsageWrap, ViewFigmaButton } from '../../../docs/components';
|
|
4
|
+
import * as Stories from './ProgressBar.stories';
|
|
5
|
+
|
|
6
|
+
<Meta title="Components / Progress Bar" />
|
|
7
|
+
|
|
8
|
+
<BackToTopButton />
|
|
9
|
+
|
|
10
|
+
<ViewFigmaButton url="https://www.figma.com/design/6NKZXZhFSExXrcbBgc6zTR/Hearth-Components---Tokens?node-id=7849-5704&t=Jg2fPJPQNzOyspmQ-4" />
|
|
11
|
+
<ViewFigmaButton url="https://www.figma.com/design/6NKZXZhFSExXrcbBgc6zTR/Hearth-Components---Tokens?node-id=7863-3977&t=Jg2fPJPQNzOyspmQ-4" />
|
|
12
|
+
|
|
13
|
+
# Progress Bar
|
|
14
|
+
|
|
15
|
+
Progress bars communicate task completion for linear flows and bounded operations. Use the linear variant for
|
|
16
|
+
inline layouts and the circular variant when space is tighter or when progress needs more emphasis.
|
|
17
|
+
|
|
18
|
+
- [Playground](#playground)
|
|
19
|
+
- [Usage](#usage)
|
|
20
|
+
- [Props](#props)
|
|
21
|
+
- [Variants](#variants)
|
|
22
|
+
- [Circular Sizes](#circular-sizes)
|
|
23
|
+
- [Examples](#examples)
|
|
24
|
+
- [Custom Value Labels](#custom-value-labels)
|
|
25
|
+
|
|
26
|
+
## Playground
|
|
27
|
+
|
|
28
|
+
<Canvas of={Stories.Playground} />
|
|
29
|
+
|
|
30
|
+
<Controls of={Stories.Playground} />
|
|
31
|
+
|
|
32
|
+
## Usage
|
|
33
|
+
|
|
34
|
+
<UsageWrap>
|
|
35
|
+
<Center>
|
|
36
|
+
<Box style={{ width: 260 }}>
|
|
37
|
+
<ProgressBar value={42} label="Uploading documents" />
|
|
38
|
+
</Box>
|
|
39
|
+
</Center>
|
|
40
|
+
</UsageWrap>
|
|
41
|
+
|
|
42
|
+
```tsx
|
|
43
|
+
import { ProgressBar } from '@utilitywarehouse/hearth-react-native';
|
|
44
|
+
|
|
45
|
+
const MyComponent = () => <ProgressBar value={42} label="Uploading documents" />;
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Props
|
|
49
|
+
|
|
50
|
+
| Property | Type | Description | Default |
|
|
51
|
+
| ----------------- | ----------------------------------------------------------------------------------------- | -------------------------------------------------------- | --------- |
|
|
52
|
+
| `variant` | `'linear' \| 'circular'` | The progress bar variant. | `linear` |
|
|
53
|
+
| `colorScheme` | `'default' \| 'success' \| 'danger'` | The color scheme for the progress indicator. | `default` |
|
|
54
|
+
| `size` | `'sm' \| 'md'` | Circular size. Only applies to the circular variant. | `md` |
|
|
55
|
+
| `value` | `number` | Current progress value. | |
|
|
56
|
+
| `min` | `number` | Minimum value. | `0` |
|
|
57
|
+
| `max` | `number` | Maximum value. | `100` |
|
|
58
|
+
| `label` | `string` | Accessible label for the progress bar. | |
|
|
59
|
+
| `hideLabel` | `boolean` | Visually hide the label and value text. | `false` |
|
|
60
|
+
| `formatValueText` | `(value: number, meta: { min: number; `<br />` max: number; percent: number }) => string` | Override the default percentage label. | |
|
|
61
|
+
| `aria-valuetext` | `string` | A human-readable text alternative for the current value. | |
|
|
62
|
+
|
|
63
|
+
## Variants
|
|
64
|
+
|
|
65
|
+
<Canvas of={Stories.Variants} />
|
|
66
|
+
|
|
67
|
+
## Circular Sizes
|
|
68
|
+
|
|
69
|
+
<Canvas of={Stories.CircularSizes} />
|
|
70
|
+
|
|
71
|
+
## Examples
|
|
72
|
+
|
|
73
|
+
### Custom Value Labels
|
|
74
|
+
|
|
75
|
+
Use `formatValueText` to show values that are not percentages, such as remaining data allowance.
|
|
76
|
+
|
|
77
|
+
<Canvas of={Stories.CustomValueLabels} />
|
|
78
|
+
|
|
79
|
+
```tsx
|
|
80
|
+
import { ProgressBar } from '@utilitywarehouse/hearth-react-native';
|
|
81
|
+
|
|
82
|
+
const MyComponent = () => (
|
|
83
|
+
<ProgressBar
|
|
84
|
+
value={68}
|
|
85
|
+
max={100}
|
|
86
|
+
label="Data allowance"
|
|
87
|
+
formatValueText={(value, { max }) => `${max - value}GB remaining`}
|
|
88
|
+
/>
|
|
89
|
+
);
|
|
90
|
+
```
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import figma from '@figma/code-connect';
|
|
2
|
+
import { ProgressBar } from '../';
|
|
3
|
+
|
|
4
|
+
figma.connect(
|
|
5
|
+
ProgressBar,
|
|
6
|
+
'https://www.figma.com/design/6NKZXZhFSExXrcbBgc6zTR/Hearth-Components---Tokens?node-id=7849-5704',
|
|
7
|
+
{
|
|
8
|
+
props: {
|
|
9
|
+
value: figma.enum('Progress', {
|
|
10
|
+
'0%': 0,
|
|
11
|
+
'10%': 10,
|
|
12
|
+
'20%': 20,
|
|
13
|
+
'30%': 30,
|
|
14
|
+
'40%': 40,
|
|
15
|
+
'50%': 50,
|
|
16
|
+
'60%': 60,
|
|
17
|
+
'70%': 70,
|
|
18
|
+
'80%': 80,
|
|
19
|
+
'90%': 90,
|
|
20
|
+
'100%': 100,
|
|
21
|
+
}),
|
|
22
|
+
colorScheme: figma.enum('Color Scheme', {
|
|
23
|
+
Default: 'default',
|
|
24
|
+
Success: 'success',
|
|
25
|
+
Danger: 'danger',
|
|
26
|
+
}),
|
|
27
|
+
label: figma.boolean('Label?', { true: figma.string('Label') }),
|
|
28
|
+
},
|
|
29
|
+
example: props => (
|
|
30
|
+
<ProgressBar
|
|
31
|
+
variant="linear"
|
|
32
|
+
value={props.value}
|
|
33
|
+
colorScheme={props.colorScheme}
|
|
34
|
+
label={props.label}
|
|
35
|
+
/>
|
|
36
|
+
),
|
|
37
|
+
}
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
figma.connect(
|
|
41
|
+
ProgressBar,
|
|
42
|
+
'https://www.figma.com/design/6NKZXZhFSExXrcbBgc6zTR/Hearth-Components---Tokens?node-id=7863-3977',
|
|
43
|
+
{
|
|
44
|
+
props: {
|
|
45
|
+
value: figma.enum('Progress', {
|
|
46
|
+
'0%': 0,
|
|
47
|
+
'10%': 10,
|
|
48
|
+
'20%': 20,
|
|
49
|
+
'30%': 30,
|
|
50
|
+
'40%': 40,
|
|
51
|
+
'50%': 50,
|
|
52
|
+
'60%': 60,
|
|
53
|
+
'70%': 70,
|
|
54
|
+
'80%': 80,
|
|
55
|
+
'90%': 90,
|
|
56
|
+
'100%': 100,
|
|
57
|
+
}),
|
|
58
|
+
colorScheme: figma.enum('Color Scheme', {
|
|
59
|
+
Default: 'default',
|
|
60
|
+
Success: 'success',
|
|
61
|
+
Danger: 'danger',
|
|
62
|
+
}),
|
|
63
|
+
size: figma.enum('Size', {
|
|
64
|
+
'SM-80': 'sm',
|
|
65
|
+
'MD-140': 'md',
|
|
66
|
+
}),
|
|
67
|
+
label: figma.boolean('Label?', { true: figma.string('Label') }),
|
|
68
|
+
},
|
|
69
|
+
example: props => (
|
|
70
|
+
<ProgressBar
|
|
71
|
+
variant="circular"
|
|
72
|
+
value={props.value}
|
|
73
|
+
colorScheme={props.colorScheme}
|
|
74
|
+
size={props.size}
|
|
75
|
+
label={props.label}
|
|
76
|
+
/>
|
|
77
|
+
),
|
|
78
|
+
}
|
|
79
|
+
);
|