@utilitywarehouse/hearth-react-native 0.4.2 → 0.6.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/.storybook/main.ts +21 -1
- package/.turbo/turbo-build.log +1 -1
- package/.turbo/turbo-lint.log +1 -1
- package/CHANGELOG.md +52 -0
- package/build/components/Alert/AlertTitle.js +6 -6
- package/build/components/Badge/Badge.js +3 -3
- package/build/components/Badge/Badge.props.d.ts +1 -0
- package/build/components/Button/ButtonRoot.js +4 -0
- package/build/components/Button/ButtonText.js +2 -2
- package/build/components/Card/CardRoot.js +1 -1
- package/build/components/Carousel/Carousel.context.d.ts +4 -0
- package/build/components/Carousel/Carousel.context.js +4 -0
- package/build/components/Carousel/Carousel.d.ts +6 -0
- package/build/components/Carousel/Carousel.js +278 -0
- package/build/components/Carousel/Carousel.props.d.ts +65 -0
- package/build/components/Carousel/Carousel.props.js +1 -0
- package/build/components/Carousel/CarouselControlItem.d.ts +24 -0
- package/build/components/Carousel/CarouselControlItem.js +64 -0
- package/build/components/Carousel/CarouselControls.d.ts +4 -0
- package/build/components/Carousel/CarouselControls.js +74 -0
- package/build/components/Carousel/CarouselItem.d.ts +6 -0
- package/build/components/Carousel/CarouselItem.js +38 -0
- package/build/components/Carousel/index.d.ts +5 -0
- package/build/components/Carousel/index.js +5 -0
- package/build/components/Container/Container.d.ts +6 -0
- package/build/components/Container/Container.js +40 -0
- package/build/components/Container/Container.props.d.ts +85 -0
- package/build/components/Container/Container.props.js +1 -0
- package/build/components/Container/index.d.ts +2 -0
- package/build/components/Container/index.js +1 -0
- package/build/components/DescriptionList/DescriptionList.d.ts +1 -1
- package/build/components/DescriptionList/DescriptionList.js +2 -2
- package/build/components/DescriptionList/DescriptionList.props.d.ts +1 -8
- package/build/components/DescriptionList/DescriptionListItem.d.ts +1 -1
- package/build/components/DescriptionList/DescriptionListItem.js +4 -3
- package/build/components/DescriptionList/DescriptionListItem.props.d.ts +3 -8
- package/build/components/IndicatorIconButton/IndicatorIconButton.d.ts +6 -0
- package/build/components/IndicatorIconButton/IndicatorIconButton.js +26 -0
- package/build/components/IndicatorIconButton/IndicatorIconButton.props.d.ts +8 -0
- package/build/components/IndicatorIconButton/IndicatorIconButton.props.js +1 -0
- package/build/components/IndicatorIconButton/index.d.ts +2 -0
- package/build/components/IndicatorIconButton/index.js +1 -0
- package/build/components/Link/LinkText.js +3 -3
- package/build/components/List/List.context.d.ts +0 -2
- package/build/components/List/List.d.ts +1 -1
- package/build/components/List/List.js +5 -5
- package/build/components/List/List.props.d.ts +1 -9
- package/build/components/List/ListAction/ListAction.d.ts +18 -0
- package/build/components/List/ListAction/ListAction.js +103 -0
- package/build/components/List/ListAction/ListAction.props.d.ts +8 -0
- package/build/components/List/ListAction/ListAction.props.js +1 -0
- package/build/components/List/ListAction/ListActionContent.d.ts +6 -0
- package/build/components/List/ListAction/ListActionContent.js +14 -0
- package/build/components/List/ListAction/ListActionText.d.ts +6 -0
- package/build/components/List/ListAction/ListActionText.js +7 -0
- package/build/components/List/ListAction/ListActionTrailingContent.d.ts +6 -0
- package/build/components/List/ListAction/ListActionTrailingContent.js +5 -0
- package/build/components/List/ListAction/ListActionTrailingIcon.d.ts +9 -0
- package/build/components/List/ListAction/ListActionTrailingIcon.js +18 -0
- package/build/components/List/ListAction/index.d.ts +6 -0
- package/build/components/List/ListAction/index.js +5 -0
- package/build/components/List/ListItem/ListItem.context.d.ts +1 -1
- package/build/components/List/ListItem/ListItem.props.d.ts +9 -5
- package/build/components/List/ListItem/ListItemRoot.d.ts +1 -1
- package/build/components/List/ListItem/ListItemRoot.js +10 -12
- package/build/components/List/ListItem/index.d.ts +4 -4
- package/build/components/List/ListItem/index.js +3 -3
- package/build/components/List/index.d.ts +1 -0
- package/build/components/List/index.js +1 -0
- package/build/components/ProgressStepper/ProgressStep.d.ts +10 -0
- package/build/components/ProgressStepper/ProgressStep.js +100 -0
- package/build/components/ProgressStepper/ProgressStepper.d.ts +6 -0
- package/build/components/ProgressStepper/ProgressStepper.js +22 -0
- package/build/components/ProgressStepper/ProgressStepper.props.d.ts +22 -0
- package/build/components/ProgressStepper/ProgressStepper.props.js +1 -0
- package/build/components/ProgressStepper/ProgressStepperRoot.d.ts +6 -0
- package/build/components/ProgressStepper/ProgressStepperRoot.js +16 -0
- package/build/components/ProgressStepper/index.d.ts +3 -0
- package/build/components/ProgressStepper/index.js +2 -0
- package/build/components/SectionHeader/SectionHeader.d.ts +1 -1
- package/build/components/SectionHeader/SectionHeader.js +6 -3
- package/build/components/SectionHeader/SectionHeader.props.d.ts +9 -16
- package/build/components/SectionHeader/SectionHeaderTrailingContent.d.ts +6 -0
- package/build/components/SectionHeader/SectionHeaderTrailingContent.js +13 -0
- package/build/components/SectionHeader/index.d.ts +1 -0
- package/build/components/SectionHeader/index.js +1 -0
- package/build/components/Tabs/Tab.js +2 -2
- package/build/components/ThemedImage/ThemedImage.d.ts +12 -0
- package/build/components/ThemedImage/ThemedImage.js +27 -0
- package/build/components/ThemedImage/ThemedImage.props.d.ts +13 -0
- package/build/components/ThemedImage/ThemedImage.props.js +1 -0
- package/build/components/ThemedImage/index.d.ts +2 -0
- package/build/components/ThemedImage/index.js +1 -0
- package/build/components/ToggleButton/ToggleButtonText.js +2 -2
- package/build/components/UnstyledIconButton/UnstyledIconButton.props.d.ts +4 -1
- package/build/components/index.d.ts +5 -0
- package/build/components/index.js +5 -0
- package/build/core/themes.d.ts +12 -24
- package/build/hooks/useStyleProps.js +1 -1
- package/build/tokens/components/dark/button.d.ts +1 -1
- package/build/tokens/components/dark/button.js +1 -1
- package/build/tokens/components/dark/dialog.d.ts +1 -0
- package/build/tokens/components/dark/dialog.js +1 -0
- package/build/tokens/components/dark/illustrations.d.ts +1 -0
- package/build/tokens/components/dark/illustrations.js +1 -0
- package/build/tokens/components/dark/toast.d.ts +4 -1
- package/build/tokens/components/dark/toast.js +4 -1
- package/build/tokens/components/light/button.d.ts +1 -1
- package/build/tokens/components/light/button.js +1 -1
- package/build/tokens/components/light/dialog.d.ts +1 -0
- package/build/tokens/components/light/dialog.js +1 -0
- package/build/tokens/components/light/illustrations.d.ts +1 -0
- package/build/tokens/components/light/illustrations.js +1 -0
- package/build/tokens/components/light/toast.d.ts +4 -1
- package/build/tokens/components/light/toast.js +4 -1
- package/build/tokens/layout.d.ts +6 -12
- package/build/tokens/layout.js +3 -6
- package/docs/components/AllComponents.web.tsx +122 -5
- package/docs/components/BadgeList.tsx +20 -56
- package/docs/components/SwitchList.tsx +4 -8
- package/docs/getting-started.mdx +30 -14
- package/docs/introduction.mdx +1 -1
- package/docs/layout-components.docs.mdx +30 -0
- package/package.json +6 -4
- package/src/components/Alert/AlertTitle.tsx +7 -7
- package/src/components/Badge/Badge.props.ts +1 -0
- package/src/components/Badge/Badge.tsx +3 -2
- package/src/components/Button/ButtonRoot.tsx +4 -0
- package/src/components/Button/ButtonText.tsx +3 -3
- package/src/components/Card/CardRoot.tsx +2 -0
- package/src/components/Carousel/Carousel.context.tsx +8 -0
- package/src/components/Carousel/Carousel.docs.mdx +389 -0
- package/src/components/Carousel/Carousel.props.ts +89 -0
- package/src/components/Carousel/Carousel.stories.tsx +317 -0
- package/src/components/Carousel/Carousel.tsx +444 -0
- package/src/components/Carousel/CarouselControlItem.tsx +87 -0
- package/src/components/Carousel/CarouselControls.tsx +150 -0
- package/src/components/Carousel/CarouselItem.tsx +68 -0
- package/src/components/Carousel/index.ts +6 -0
- package/src/components/Container/Container.docs.mdx +168 -0
- package/src/components/Container/Container.props.ts +89 -0
- package/src/components/Container/Container.stories.tsx +274 -0
- package/src/components/Container/Container.tsx +52 -0
- package/src/components/Container/index.tsx +2 -0
- package/src/components/DescriptionList/DescriptionList.docs.mdx +24 -27
- package/src/components/DescriptionList/DescriptionList.props.ts +1 -8
- package/src/components/DescriptionList/DescriptionList.stories.tsx +13 -19
- package/src/components/DescriptionList/DescriptionList.tsx +2 -14
- package/src/components/DescriptionList/DescriptionListItem.props.ts +3 -8
- package/src/components/DescriptionList/DescriptionListItem.tsx +13 -21
- package/src/components/IndicatorIconButton/IndicatorIconButton.docs.mdx +85 -0
- package/src/components/IndicatorIconButton/IndicatorIconButton.props.ts +12 -0
- package/src/components/IndicatorIconButton/IndicatorIconButton.stories.tsx +142 -0
- package/src/components/IndicatorIconButton/IndicatorIconButton.tsx +36 -0
- package/src/components/IndicatorIconButton/index.tsx +2 -0
- package/src/components/Link/LinkText.tsx +4 -4
- package/src/components/List/List.context.ts +0 -1
- package/src/components/List/List.docs.mdx +376 -179
- package/src/components/List/List.props.ts +1 -9
- package/src/components/List/List.stories.tsx +289 -38
- package/src/components/List/List.tsx +5 -26
- package/src/components/List/ListAction/ListAction.props.ts +10 -0
- package/src/components/List/ListAction/ListAction.tsx +133 -0
- package/src/components/List/ListAction/ListActionContent.tsx +21 -0
- package/src/components/List/ListAction/ListActionText.tsx +14 -0
- package/src/components/List/ListAction/ListActionTrailingContent.tsx +9 -0
- package/src/components/List/ListAction/ListActionTrailingIcon.tsx +32 -0
- package/src/components/List/ListAction/index.ts +6 -0
- package/src/components/List/ListItem/ListItem.context.ts +1 -1
- package/src/components/List/ListItem/ListItem.props.ts +9 -5
- package/src/components/List/ListItem/ListItemRoot.tsx +18 -14
- package/src/components/List/ListItem/index.ts +4 -4
- package/src/components/List/index.ts +1 -0
- package/src/components/ProgressStepper/ProgressStep.tsx +134 -0
- package/src/components/ProgressStepper/ProgressStepper.docs.mdx +87 -0
- package/src/components/ProgressStepper/ProgressStepper.props.ts +27 -0
- package/src/components/ProgressStepper/ProgressStepper.stories.tsx +108 -0
- package/src/components/ProgressStepper/ProgressStepper.tsx +26 -0
- package/src/components/ProgressStepper/ProgressStepperRoot.tsx +32 -0
- package/src/components/ProgressStepper/index.ts +3 -0
- package/src/components/SectionHeader/SectionHeader.props.ts +9 -16
- package/src/components/SectionHeader/SectionHeader.stories.tsx +28 -18
- package/src/components/SectionHeader/SectionHeader.tsx +18 -19
- package/src/components/SectionHeader/SectionHeaderTrailingContent.tsx +20 -0
- package/src/components/SectionHeader/Sectionheader.docs.mdx +9 -24
- package/src/components/SectionHeader/index.ts +1 -0
- package/src/components/Switch/Switch.docs.mdx +0 -4
- package/src/components/Tabs/Tab.tsx +4 -2
- package/src/components/ThemedImage/ThemedImage.docs.mdx +208 -0
- package/src/components/ThemedImage/ThemedImage.props.ts +15 -0
- package/src/components/ThemedImage/ThemedImage.stories.tsx +175 -0
- package/src/components/ThemedImage/ThemedImage.tsx +34 -0
- package/src/components/ThemedImage/index.tsx +2 -0
- package/src/components/ToggleButton/ToggleButtonText.tsx +3 -3
- package/src/components/UnstyledIconButton/UnstyledIconButton.props.ts +2 -1
- package/src/components/index.ts +5 -0
- package/src/hooks/useStyleProps.ts +1 -1
- package/src/tokens/components/dark/button.ts +1 -1
- package/src/tokens/components/dark/dialog.ts +1 -0
- package/src/tokens/components/dark/illustrations.ts +1 -0
- package/src/tokens/components/dark/toast.ts +4 -1
- package/src/tokens/components/light/button.ts +1 -1
- package/src/tokens/components/light/dialog.ts +1 -0
- package/src/tokens/components/light/illustrations.ts +1 -0
- package/src/tokens/components/light/toast.ts +4 -1
- package/src/tokens/layout.ts +3 -6
- package/src/vite-env.d.ts +6 -0
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { default as ListAction } from './ListAction';
|
|
2
|
+
export type { default as ListActionProps } from './ListAction.props';
|
|
3
|
+
export { default as ListActionContent } from './ListActionContent';
|
|
4
|
+
export { default as ListActionText } from './ListActionText';
|
|
5
|
+
export { default as ListActionTrailingContent } from './ListActionTrailingContent';
|
|
6
|
+
export { default as ListActionTrailingIcon } from './ListActionTrailingIcon';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createContext, useContext } from 'react';
|
|
2
2
|
import ListItemProps from './ListItem.props';
|
|
3
3
|
|
|
4
|
-
export interface IListItemContext extends Pick<ListItemProps, '
|
|
4
|
+
export interface IListItemContext extends Pick<ListItemProps, 'loading' | 'disabled'> {
|
|
5
5
|
showPressed?: boolean;
|
|
6
6
|
active?: boolean;
|
|
7
7
|
}
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import type { PressableProps, ViewProps } from 'react-native';
|
|
2
|
-
import
|
|
2
|
+
import BadgeProps from '../../Badge/Badge.props';
|
|
3
3
|
|
|
4
4
|
interface ListItemBaseProps extends Omit<PressableProps, 'children'> {
|
|
5
|
-
divider?: boolean;
|
|
6
|
-
dividerColor?: ColorValue;
|
|
7
5
|
loading?: boolean;
|
|
8
6
|
disabled?: boolean;
|
|
9
7
|
variant?: 'subtle' | 'emphasis';
|
|
@@ -12,18 +10,24 @@ interface ListItemBaseProps extends Omit<PressableProps, 'children'> {
|
|
|
12
10
|
|
|
13
11
|
export interface ListItemWithChildren extends ListItemBaseProps {
|
|
14
12
|
children: ViewProps['children'];
|
|
15
|
-
|
|
13
|
+
heading?: never;
|
|
16
14
|
helperText?: never;
|
|
17
15
|
leadingContent?: never;
|
|
18
16
|
trailingContent?: never;
|
|
17
|
+
numericValue?: never;
|
|
18
|
+
badge?: never;
|
|
19
|
+
badgePosition?: never;
|
|
19
20
|
}
|
|
20
21
|
|
|
21
22
|
export interface ListItemWithoutChildren extends ListItemBaseProps {
|
|
22
23
|
children?: never;
|
|
23
|
-
|
|
24
|
+
heading: string;
|
|
24
25
|
helperText?: string;
|
|
25
26
|
leadingContent?: ViewProps['children'];
|
|
26
27
|
trailingContent?: ViewProps['children'];
|
|
28
|
+
numericValue?: string | number;
|
|
29
|
+
badge?: BadgeProps;
|
|
30
|
+
badgePosition?: 'top' | 'bottom';
|
|
27
31
|
}
|
|
28
32
|
|
|
29
33
|
type ListItemProps = ListItemWithChildren | ListItemWithoutChildren;
|
|
@@ -2,6 +2,8 @@ import { ChevronRightSmallIcon } from '@utilitywarehouse/hearth-react-native-ico
|
|
|
2
2
|
import { useMemo } from 'react';
|
|
3
3
|
import { Pressable, ViewStyle } from 'react-native';
|
|
4
4
|
import { StyleSheet } from 'react-native-unistyles';
|
|
5
|
+
import { Badge } from '../../Badge';
|
|
6
|
+
import { DetailText } from '../../DetailText';
|
|
5
7
|
import { Skeleton } from '../../Skeleton';
|
|
6
8
|
import { useListContext } from '../List.context';
|
|
7
9
|
import { IListItemContext, ListItemContext } from './ListItem.context';
|
|
@@ -14,16 +16,18 @@ import ListItemTrailingContent from './ListItemTrailingContent';
|
|
|
14
16
|
import ListItemTrailingIcon from './ListItemTrailingIcon';
|
|
15
17
|
|
|
16
18
|
const ListItemRoot = ({
|
|
17
|
-
|
|
19
|
+
heading,
|
|
18
20
|
helperText,
|
|
19
21
|
leadingContent,
|
|
20
22
|
trailingContent,
|
|
21
23
|
disabled,
|
|
22
|
-
divider,
|
|
23
24
|
loading,
|
|
24
25
|
children,
|
|
25
26
|
states,
|
|
26
27
|
variant = 'subtle',
|
|
28
|
+
badge,
|
|
29
|
+
badgePosition = 'bottom',
|
|
30
|
+
numericValue,
|
|
27
31
|
...props
|
|
28
32
|
}: ListItemProps & { states?: { active?: boolean; disabled?: boolean } }) => {
|
|
29
33
|
const { onPress } = props;
|
|
@@ -42,7 +46,6 @@ const ListItemRoot = ({
|
|
|
42
46
|
|
|
43
47
|
const isLoading = loading || listContext?.loading;
|
|
44
48
|
const showPressed = isLoading ? false : !!onPress;
|
|
45
|
-
const showDivider = listContext?.divider ?? divider;
|
|
46
49
|
const isDisabled = disabled || listContext?.disabled || false;
|
|
47
50
|
const listItemVariant = getListContainer() || variant;
|
|
48
51
|
|
|
@@ -50,7 +53,6 @@ const ListItemRoot = ({
|
|
|
50
53
|
const loadingTestID = isLoading ? `${testID}-loading` : testID;
|
|
51
54
|
|
|
52
55
|
styles.useVariants({
|
|
53
|
-
divider: showDivider,
|
|
54
56
|
variant: listItemVariant,
|
|
55
57
|
showPressed,
|
|
56
58
|
active,
|
|
@@ -63,12 +65,11 @@ const ListItemRoot = ({
|
|
|
63
65
|
const value: IListItemContext = useMemo(() => {
|
|
64
66
|
return {
|
|
65
67
|
showPressed,
|
|
66
|
-
divider: showDivider,
|
|
67
68
|
active,
|
|
68
69
|
loading: isLoading,
|
|
69
70
|
disabled: isDisabled,
|
|
70
71
|
};
|
|
71
|
-
}, [active, showPressed,
|
|
72
|
+
}, [active, showPressed, isLoading, isDisabled]);
|
|
72
73
|
|
|
73
74
|
if (loading || listContext?.loading) {
|
|
74
75
|
return (
|
|
@@ -95,6 +96,7 @@ const ListItemRoot = ({
|
|
|
95
96
|
testID={testID}
|
|
96
97
|
style={[styles.container, props.style as ViewStyle]}
|
|
97
98
|
disabled={isDisabled}
|
|
99
|
+
accessibilityRole={onPress ? 'button' : undefined}
|
|
98
100
|
>
|
|
99
101
|
{children ? (
|
|
100
102
|
children
|
|
@@ -104,13 +106,16 @@ const ListItemRoot = ({
|
|
|
104
106
|
<ListItemLeadingContent>{leadingContent}</ListItemLeadingContent>
|
|
105
107
|
) : null}
|
|
106
108
|
<ListItemContent>
|
|
107
|
-
<
|
|
109
|
+
{badgePosition === 'top' && badge ? <Badge {...badge} /> : null}
|
|
110
|
+
<ListItemText>{heading}</ListItemText>
|
|
108
111
|
{helperText ? <ListItemHelperText>{helperText}</ListItemHelperText> : null}
|
|
112
|
+
{badgePosition === 'bottom' && badge ? <Badge {...badge} /> : null}
|
|
109
113
|
</ListItemContent>
|
|
114
|
+
{!!numericValue && <DetailText size="lg">{numericValue}</DetailText>}
|
|
110
115
|
{trailingContent ? (
|
|
111
116
|
<ListItemTrailingContent>{trailingContent}</ListItemTrailingContent>
|
|
112
117
|
) : onPress ? (
|
|
113
|
-
<ListItemTrailingContent>
|
|
118
|
+
<ListItemTrailingContent style={styles.centeredTrailingIcon}>
|
|
114
119
|
<ListItemTrailingIcon as={ChevronRightSmallIcon} />
|
|
115
120
|
</ListItemTrailingContent>
|
|
116
121
|
) : null}
|
|
@@ -129,13 +134,9 @@ const styles = StyleSheet.create(theme => ({
|
|
|
129
134
|
paddingHorizontal: theme.components.list.item.functional.padding,
|
|
130
135
|
flexDirection: 'row',
|
|
131
136
|
gap: theme.components.list.item.gap,
|
|
137
|
+
borderTopWidth: theme.borderWidth['1'],
|
|
138
|
+
borderStyle: 'solid',
|
|
132
139
|
variants: {
|
|
133
|
-
divider: {
|
|
134
|
-
true: {
|
|
135
|
-
borderTopWidth: theme.borderWidth['1'],
|
|
136
|
-
borderStyle: 'solid',
|
|
137
|
-
},
|
|
138
|
-
},
|
|
139
140
|
isFirstChild: {
|
|
140
141
|
true: {
|
|
141
142
|
borderTopWidth: 0,
|
|
@@ -197,6 +198,9 @@ const styles = StyleSheet.create(theme => ({
|
|
|
197
198
|
},
|
|
198
199
|
],
|
|
199
200
|
},
|
|
201
|
+
centeredTrailingIcon: {
|
|
202
|
+
justifyContent: 'center',
|
|
203
|
+
},
|
|
200
204
|
}));
|
|
201
205
|
|
|
202
206
|
export default ListItemRoot;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
export { default as ListItem } from './ListItem';
|
|
2
|
-
export { default as ListItemIcon } from './ListItemIcon';
|
|
3
|
-
export { default as ListItemContent } from './ListItemContent';
|
|
4
2
|
export type { default as ListItemProps } from './ListItem.props';
|
|
3
|
+
export { default as ListItemContent } from './ListItemContent';
|
|
4
|
+
export { default as ListItemHelperText } from './ListItemHelperText';
|
|
5
|
+
export { default as ListItemIcon } from './ListItemIcon';
|
|
5
6
|
export { default as ListItemLeadingContent } from './ListItemLeadingContent';
|
|
7
|
+
export { default as ListItemText } from './ListItemText';
|
|
6
8
|
export { default as ListItemTrailingContent } from './ListItemTrailingContent';
|
|
7
9
|
export { default as ListItemTrailingIcon } from './ListItemTrailingIcon';
|
|
8
|
-
export { default as ListItemHelperText } from './ListItemHelperText';
|
|
9
|
-
export { default as ListItemText } from './ListItemText';
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { View } from 'react-native';
|
|
3
|
+
import { StyleSheet } from 'react-native-unistyles';
|
|
4
|
+
import { TickSmallIcon } from '@utilitywarehouse/hearth-react-native-icons';
|
|
5
|
+
import { Icon } from '../Icon';
|
|
6
|
+
import { BodyText } from '../BodyText';
|
|
7
|
+
import { ProgressStepProps } from './ProgressStepper.props';
|
|
8
|
+
|
|
9
|
+
interface ProgressStepInternalProps extends ProgressStepProps {
|
|
10
|
+
index?: number;
|
|
11
|
+
isLast?: boolean;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const ProgressStep = ({ status, index = 0, isLast = false, ...rest }: ProgressStepInternalProps) => {
|
|
15
|
+
styles.useVariants({ status, isLast });
|
|
16
|
+
|
|
17
|
+
const renderStepNumber = () => {
|
|
18
|
+
return (
|
|
19
|
+
<BodyText size="md" weight="semibold" style={styles.text}>
|
|
20
|
+
{index + 1}
|
|
21
|
+
</BodyText>
|
|
22
|
+
);
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
return (
|
|
26
|
+
<View
|
|
27
|
+
style={styles.container}
|
|
28
|
+
accessible
|
|
29
|
+
aria-label={`Step ${index + 1}, ${rest.id}, ${status}`}
|
|
30
|
+
{...rest}
|
|
31
|
+
>
|
|
32
|
+
<View style={styles.step}>
|
|
33
|
+
{status === 'complete' ? (
|
|
34
|
+
<Icon as={TickSmallIcon} width={20} height={20} style={styles.text} />
|
|
35
|
+
) : status === 'active' ? (
|
|
36
|
+
<View style={styles.inner}>{renderStepNumber()}</View>
|
|
37
|
+
) : (
|
|
38
|
+
renderStepNumber()
|
|
39
|
+
)}
|
|
40
|
+
</View>
|
|
41
|
+
{!isLast && <View style={styles.connector} />}
|
|
42
|
+
</View>
|
|
43
|
+
);
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
ProgressStep.displayName = 'ProgressStep';
|
|
47
|
+
|
|
48
|
+
const styles = StyleSheet.create(theme => ({
|
|
49
|
+
container: {
|
|
50
|
+
flexDirection: 'row',
|
|
51
|
+
alignItems: 'center',
|
|
52
|
+
variants: {
|
|
53
|
+
isLast: {
|
|
54
|
+
true: {
|
|
55
|
+
flex: 0,
|
|
56
|
+
_web: {
|
|
57
|
+
flex: 'none',
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
false: {
|
|
61
|
+
flex: 1,
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
step: {
|
|
67
|
+
width: theme.components.progressStepper.indicator.width,
|
|
68
|
+
height: theme.components.progressStepper.indicator.height,
|
|
69
|
+
borderRadius: theme.borderRadius.full,
|
|
70
|
+
alignItems: 'center',
|
|
71
|
+
justifyContent: 'center',
|
|
72
|
+
variants: {
|
|
73
|
+
status: {
|
|
74
|
+
complete: {
|
|
75
|
+
backgroundColor: theme.color.surface.brand.default,
|
|
76
|
+
},
|
|
77
|
+
active: {
|
|
78
|
+
backgroundColor: theme.color.surface.brand.default,
|
|
79
|
+
padding: theme.borderWidth[2],
|
|
80
|
+
},
|
|
81
|
+
incomplete: {
|
|
82
|
+
borderWidth: theme.components.progressStepper.indicator.future.borderWidth,
|
|
83
|
+
borderColor: theme.color.border.subtle,
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
inner: {
|
|
89
|
+
width: theme.components.progressStepper.indicator.width - theme.borderWidth[2] * 2,
|
|
90
|
+
height: theme.components.progressStepper.indicator.height - theme.borderWidth[2] * 2,
|
|
91
|
+
borderRadius: theme.borderRadius.full,
|
|
92
|
+
backgroundColor: theme.color.surface.brand.default,
|
|
93
|
+
borderWidth: theme.borderWidth[2],
|
|
94
|
+
borderColor: theme.color.surface.neutral.subtle,
|
|
95
|
+
alignItems: 'center',
|
|
96
|
+
justifyContent: 'center',
|
|
97
|
+
},
|
|
98
|
+
text: {
|
|
99
|
+
variants: {
|
|
100
|
+
status: {
|
|
101
|
+
complete: {
|
|
102
|
+
color: theme.color.text.inverted,
|
|
103
|
+
},
|
|
104
|
+
active: {
|
|
105
|
+
color: theme.color.text.inverted,
|
|
106
|
+
// NOTE: Adjust lineHeight to vertically center the text within the smaller inner circle
|
|
107
|
+
lineHeight: theme.lineHeight[500] - theme.borderWidth[2] * 2,
|
|
108
|
+
},
|
|
109
|
+
incomplete: {
|
|
110
|
+
color: theme.color.text.primary,
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
connector: {
|
|
116
|
+
flex: 1,
|
|
117
|
+
height: theme.components.progressStepper.bar.height,
|
|
118
|
+
variants: {
|
|
119
|
+
status: {
|
|
120
|
+
complete: {
|
|
121
|
+
backgroundColor: theme.components.progressStepper.bar.complete.backgroundColor,
|
|
122
|
+
},
|
|
123
|
+
active: {
|
|
124
|
+
backgroundColor: theme.color.border.subtle,
|
|
125
|
+
},
|
|
126
|
+
incomplete: {
|
|
127
|
+
backgroundColor: theme.color.border.subtle,
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
},
|
|
131
|
+
},
|
|
132
|
+
}));
|
|
133
|
+
|
|
134
|
+
export default ProgressStep;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { Canvas, Meta } from '@storybook/addon-docs/blocks';
|
|
2
|
+
import { BackToTopButton, ViewFigmaButton } from '../../../docs/components';
|
|
3
|
+
import * as ProgressStepperStories from './ProgressStepper.stories';
|
|
4
|
+
|
|
5
|
+
<Meta title="Components / Progress Stepper" />
|
|
6
|
+
|
|
7
|
+
<ViewFigmaButton url="https://www.figma.com/design/6NKZXZhFSExXrcbBgc6zTR/Hearth-Components---Tokens?node-id=6056-1987" />
|
|
8
|
+
|
|
9
|
+
<BackToTopButton />
|
|
10
|
+
|
|
11
|
+
# Progress Stepper
|
|
12
|
+
|
|
13
|
+
A form helper component that displays a series of dots connected by lines, showing the progress through a multi-step process. Each step can be marked as completed, active, or uncompleted.
|
|
14
|
+
|
|
15
|
+
- [Usage](#usage)
|
|
16
|
+
- [Examples](#examples)
|
|
17
|
+
- [API](#api)
|
|
18
|
+
- [Step Statuses](#step-statuses-1)
|
|
19
|
+
- [Accessibility](#accessibility)
|
|
20
|
+
- [Best Practices](#best-practices)
|
|
21
|
+
|
|
22
|
+
## Usage
|
|
23
|
+
|
|
24
|
+
The `ProgressStepper` component uses a compound component pattern, making it easy to define steps declaratively. It provides visual feedback about complete steps, the current active step, and remaining incomplete steps.
|
|
25
|
+
|
|
26
|
+
### Basic Usage
|
|
27
|
+
|
|
28
|
+
```tsx
|
|
29
|
+
import { ProgressStepper, ProgressStep } from '@hearth/react-native';
|
|
30
|
+
|
|
31
|
+
<ProgressStepper>
|
|
32
|
+
<ProgressStep id={"1"} status="complete" />
|
|
33
|
+
<ProgressStep id={"2"} status="complete" />
|
|
34
|
+
<ProgressStep id={"3"} status="active" />
|
|
35
|
+
<ProgressStep id={"4"} status="incomplete" />
|
|
36
|
+
<ProgressStep id={"5"} status="incomplete" />
|
|
37
|
+
</ProgressStepper>
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Examples
|
|
41
|
+
|
|
42
|
+
### Default Layout
|
|
43
|
+
|
|
44
|
+
<Canvas of={ProgressStepperStories.Playground} />
|
|
45
|
+
|
|
46
|
+
### Step Statuses
|
|
47
|
+
|
|
48
|
+
See how different step statuses are visualized:
|
|
49
|
+
|
|
50
|
+
<Canvas of={ProgressStepperStories.StepStatuses} />
|
|
51
|
+
|
|
52
|
+
### Basic
|
|
53
|
+
|
|
54
|
+
<Canvas of={ProgressStepperStories.BasicExample} />
|
|
55
|
+
|
|
56
|
+
## API
|
|
57
|
+
|
|
58
|
+
### Progress Stepper Props
|
|
59
|
+
|
|
60
|
+
| Prop | Type | Default | Description |
|
|
61
|
+
|------|------|---------|-------------|
|
|
62
|
+
| `children` | `ReactNode` | Required | `ProgressStep` components |
|
|
63
|
+
|
|
64
|
+
### Progress Step Props
|
|
65
|
+
|
|
66
|
+
| Prop | Type | Default | Description |
|
|
67
|
+
|------|------|---------|-------------|
|
|
68
|
+
| `id` | `string` | Required | Unique identifier for the step |
|
|
69
|
+
| `status` | `'complete' \| 'active' \| 'incomplete'` | Required | Current status of the step |
|
|
70
|
+
|
|
71
|
+
## Step Statuses
|
|
72
|
+
|
|
73
|
+
- **complete**: Step has been finished, shows a checkmark icon
|
|
74
|
+
- **active**: Current step, shows a number with highlighted background
|
|
75
|
+
- **incomplete**: Future step, shows a number with muted styling
|
|
76
|
+
|
|
77
|
+
## Accessibility
|
|
78
|
+
|
|
79
|
+
- Each step is properly labeled for screen readers
|
|
80
|
+
- The component follows WCAG guidelines for color contrast
|
|
81
|
+
- Progress indication is communicated through both visual and textual means
|
|
82
|
+
|
|
83
|
+
## Best Practices
|
|
84
|
+
|
|
85
|
+
1. **Keep it simple** - The stepper focuses on essential functionality without complexity
|
|
86
|
+
1. **Indicate progress clearly** - Make sure users understand how many steps remain
|
|
87
|
+
1. **Use meaningful IDs** - Choose IDs that make sense for your specific use case (numbers, step names, etc.)
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { ViewProps } from 'react-native';
|
|
2
|
+
|
|
3
|
+
export type StepStatus = 'complete' | 'active' | 'incomplete';
|
|
4
|
+
|
|
5
|
+
export interface ProgressStepperProps extends ViewProps {
|
|
6
|
+
/**
|
|
7
|
+
* Child ProgressStep components
|
|
8
|
+
*/
|
|
9
|
+
children: React.ReactNode;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface ProgressStepProps extends ViewProps {
|
|
13
|
+
/**
|
|
14
|
+
* Unique identifier for the step
|
|
15
|
+
*/
|
|
16
|
+
id: string;
|
|
17
|
+
/**
|
|
18
|
+
* Current status of the step
|
|
19
|
+
*/
|
|
20
|
+
status: StepStatus;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface ProgressStepperRootProps extends ViewProps {
|
|
24
|
+
children: React.ReactNode;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export default ProgressStepperProps;
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Meta, StoryObj } from '@storybook/react-vite';
|
|
3
|
+
import { ProgressStepper, ProgressStep } from '.';
|
|
4
|
+
import { VariantTitle } from '../../../docs/components';
|
|
5
|
+
import { BodyText } from '../BodyText';
|
|
6
|
+
import { Flex } from '../Flex';
|
|
7
|
+
import { Heading } from '../Heading';
|
|
8
|
+
|
|
9
|
+
const meta = {
|
|
10
|
+
title: 'Stories / ProgressStepper',
|
|
11
|
+
component: ProgressStepper,
|
|
12
|
+
parameters: {
|
|
13
|
+
layout: 'centered',
|
|
14
|
+
},
|
|
15
|
+
} satisfies Meta<typeof ProgressStepper>;
|
|
16
|
+
|
|
17
|
+
export default meta;
|
|
18
|
+
type Story = StoryObj<typeof meta>;
|
|
19
|
+
|
|
20
|
+
export const Playground: Story = {
|
|
21
|
+
args: {
|
|
22
|
+
children: (
|
|
23
|
+
<Flex space="xl" direction="column" align="center" style={{ flex: 1, minWidth: 200 }}>
|
|
24
|
+
<ProgressStepper>
|
|
25
|
+
<ProgressStep id={'1'} status="complete" />
|
|
26
|
+
<ProgressStep id={'2'} status="complete" />
|
|
27
|
+
<ProgressStep id={'3'} status="active" />
|
|
28
|
+
<ProgressStep id={'4'} status="incomplete" />
|
|
29
|
+
</ProgressStepper>
|
|
30
|
+
<Flex direction="row" space="lg" style={{ width: '100%' }}>
|
|
31
|
+
<ProgressStep id={'1'} status="complete" />
|
|
32
|
+
</Flex>
|
|
33
|
+
<Flex direction="row" space="lg" style={{ width: '100%' }}>
|
|
34
|
+
<ProgressStep id={'3'} status="active" />
|
|
35
|
+
</Flex>
|
|
36
|
+
<Flex direction="row" space="lg" style={{ width: '100%' }}>
|
|
37
|
+
<ProgressStep id={'5'} status="incomplete" />
|
|
38
|
+
</Flex>
|
|
39
|
+
</Flex>
|
|
40
|
+
),
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export const StepStatuses: Story = {
|
|
45
|
+
args: {
|
|
46
|
+
children: <></>,
|
|
47
|
+
},
|
|
48
|
+
parameters: {
|
|
49
|
+
controls: { exclude: ['space'] },
|
|
50
|
+
},
|
|
51
|
+
render: props => {
|
|
52
|
+
return (
|
|
53
|
+
<Flex space="xl" direction="column" align="center">
|
|
54
|
+
<VariantTitle title="All Uncompleted Steps">
|
|
55
|
+
<ProgressStepper {...props}>
|
|
56
|
+
<ProgressStep id={'1'} status="incomplete" />
|
|
57
|
+
<ProgressStep id={'2'} status="incomplete" />
|
|
58
|
+
<ProgressStep id={'3'} status="incomplete" />
|
|
59
|
+
</ProgressStepper>
|
|
60
|
+
</VariantTitle>
|
|
61
|
+
<VariantTitle title="One Active Step">
|
|
62
|
+
<ProgressStepper {...props}>
|
|
63
|
+
<ProgressStep id={'1'} status="active" />
|
|
64
|
+
<ProgressStep id={'2'} status="incomplete" />
|
|
65
|
+
<ProgressStep id={'3'} status="incomplete" />
|
|
66
|
+
</ProgressStepper>
|
|
67
|
+
</VariantTitle>
|
|
68
|
+
<VariantTitle title="Mixed Statuses">
|
|
69
|
+
<ProgressStepper {...props}>
|
|
70
|
+
<ProgressStep id={'1'} status="complete" />
|
|
71
|
+
<ProgressStep id={'2'} status="complete" />
|
|
72
|
+
<ProgressStep id={'3'} status="active" />
|
|
73
|
+
<ProgressStep id={'4'} status="incomplete" />
|
|
74
|
+
</ProgressStepper>
|
|
75
|
+
</VariantTitle>
|
|
76
|
+
<VariantTitle title="All Completed">
|
|
77
|
+
<ProgressStepper {...props}>
|
|
78
|
+
<ProgressStep id={'1'} status="complete" />
|
|
79
|
+
<ProgressStep id={'2'} status="complete" />
|
|
80
|
+
<ProgressStep id={'3'} status="complete" />
|
|
81
|
+
</ProgressStepper>
|
|
82
|
+
</VariantTitle>
|
|
83
|
+
</Flex>
|
|
84
|
+
);
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
export const BasicExample: Story = {
|
|
89
|
+
args: {
|
|
90
|
+
children: <></>,
|
|
91
|
+
},
|
|
92
|
+
render: props => {
|
|
93
|
+
return (
|
|
94
|
+
<Flex space="lg" direction="column" align="center">
|
|
95
|
+
<Heading size="md">Progress Stepper</Heading>
|
|
96
|
+
<BodyText>Shows progress through multi-step processes</BodyText>
|
|
97
|
+
<ProgressStepper {...props}>
|
|
98
|
+
<ProgressStep id="services-data" status="complete" />
|
|
99
|
+
<ProgressStep id="customer-data" status="complete" />
|
|
100
|
+
<ProgressStep id="shipping-data" status="active" />
|
|
101
|
+
<ProgressStep id="payment-data" status="incomplete" />
|
|
102
|
+
<ProgressStep id="summary" status="incomplete" />
|
|
103
|
+
</ProgressStepper>
|
|
104
|
+
<BodyText>Step 3 of 5</BodyText>
|
|
105
|
+
</Flex>
|
|
106
|
+
);
|
|
107
|
+
},
|
|
108
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import React, { useMemo, Children, cloneElement, isValidElement } from 'react';
|
|
2
|
+
import ProgressStepperProps from './ProgressStepper.props';
|
|
3
|
+
import ProgressStepperRoot from './ProgressStepperRoot';
|
|
4
|
+
|
|
5
|
+
const ProgressStepper = ({ children, ...rest }: ProgressStepperProps) => {
|
|
6
|
+
// Process children to add index and isLast props
|
|
7
|
+
const processedChildren = useMemo(() => {
|
|
8
|
+
const childrenArray = Children.toArray(children);
|
|
9
|
+
return childrenArray.map((child, index) => {
|
|
10
|
+
if (isValidElement(child)) {
|
|
11
|
+
return cloneElement(child, {
|
|
12
|
+
...(child.props as any),
|
|
13
|
+
index,
|
|
14
|
+
isLast: index === childrenArray.length - 1,
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
return child;
|
|
18
|
+
});
|
|
19
|
+
}, [children]);
|
|
20
|
+
|
|
21
|
+
return <ProgressStepperRoot {...rest}>{processedChildren}</ProgressStepperRoot>;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
ProgressStepper.displayName = 'ProgressStepper';
|
|
25
|
+
|
|
26
|
+
export default ProgressStepper;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { View, ViewStyle } from 'react-native';
|
|
3
|
+
import { StyleSheet } from 'react-native-unistyles';
|
|
4
|
+
import { ProgressStepperRootProps } from './ProgressStepper.props';
|
|
5
|
+
|
|
6
|
+
const ProgressStepperRoot = ({
|
|
7
|
+
children,
|
|
8
|
+
style,
|
|
9
|
+
...rest
|
|
10
|
+
}: ProgressStepperRootProps) => {
|
|
11
|
+
return (
|
|
12
|
+
<View
|
|
13
|
+
style={[styles.root, style as ViewStyle]}
|
|
14
|
+
{...rest}
|
|
15
|
+
>
|
|
16
|
+
{children}
|
|
17
|
+
</View>
|
|
18
|
+
);
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
ProgressStepperRoot.displayName = 'ProgressStepperRoot';
|
|
22
|
+
|
|
23
|
+
const styles = StyleSheet.create(() => ({
|
|
24
|
+
root: {
|
|
25
|
+
flexDirection: 'row',
|
|
26
|
+
alignItems: 'center',
|
|
27
|
+
justifyContent: 'space-between',
|
|
28
|
+
width: '100%',
|
|
29
|
+
},
|
|
30
|
+
}));
|
|
31
|
+
|
|
32
|
+
export default ProgressStepperRoot;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type {
|
|
1
|
+
import { Ref } from 'react';
|
|
2
|
+
import type { View, ViewProps } from 'react-native';
|
|
3
|
+
import BadgeProps from '../Badge/Badge.props';
|
|
3
4
|
|
|
4
5
|
interface SectionHeaderBaseProps extends Omit<ViewProps, 'children'> {
|
|
5
6
|
ref?: Ref<View>;
|
|
@@ -9,26 +10,18 @@ export interface SectionHeaderWithChildren extends SectionHeaderBaseProps {
|
|
|
9
10
|
children: ViewProps['children'];
|
|
10
11
|
heading?: never;
|
|
11
12
|
helperText?: never;
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
linkTarget?: never;
|
|
16
|
-
linkIcon?: never;
|
|
17
|
-
linkIconPosition?: never;
|
|
18
|
-
linkShowIcon?: never;
|
|
13
|
+
trailingContent?: never;
|
|
14
|
+
badge?: never;
|
|
15
|
+
invalidText?: never;
|
|
19
16
|
}
|
|
20
17
|
|
|
21
18
|
export interface SectionHeaderWithoutChildren extends SectionHeaderBaseProps {
|
|
22
19
|
children?: never;
|
|
23
20
|
heading: string;
|
|
24
21
|
helperText?: string;
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
linkTarget?: '_blank' | '_self' | '_parent' | '_top';
|
|
29
|
-
linkIcon?: ComponentType;
|
|
30
|
-
linkIconPosition?: 'left' | 'right';
|
|
31
|
-
linkShowIcon?: boolean;
|
|
22
|
+
trailingContent?: React.ReactNode;
|
|
23
|
+
badge?: BadgeProps;
|
|
24
|
+
invalidText?: string;
|
|
32
25
|
}
|
|
33
26
|
|
|
34
27
|
type SectionHeaderProps = SectionHeaderWithChildren | SectionHeaderWithoutChildren;
|