@utilitywarehouse/hearth-react-native 0.27.2 → 0.28.0-testid-fix-1
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 +5 -4
- package/.turbo/turbo-lint.log +70 -69
- package/CHANGELOG.md +149 -0
- package/build/components/Button/ButtonRoot.js +8 -0
- package/build/components/Combobox/Combobox.context.d.ts +13 -0
- package/build/components/Combobox/Combobox.context.js +9 -0
- package/build/components/Combobox/Combobox.d.ts +6 -0
- package/build/components/Combobox/Combobox.js +246 -0
- package/build/components/Combobox/Combobox.props.d.ts +180 -0
- package/build/components/Combobox/Combobox.props.js +1 -0
- package/build/components/Combobox/ComboboxOption.d.ts +6 -0
- package/build/components/Combobox/ComboboxOption.js +56 -0
- package/build/components/Combobox/index.d.ts +4 -0
- package/build/components/Combobox/index.js +3 -0
- package/build/components/DatePicker/TimePicker.d.ts +3 -0
- package/build/components/DatePicker/TimePicker.js +84 -0
- package/build/components/DatePicker/time-picker/animated-math.d.ts +4 -0
- package/build/components/DatePicker/time-picker/animated-math.js +19 -0
- package/build/components/DatePicker/time-picker/period-native.d.ts +6 -0
- package/build/components/DatePicker/time-picker/period-native.js +17 -0
- package/build/components/DatePicker/time-picker/period-picker.d.ts +6 -0
- package/build/components/DatePicker/time-picker/period-picker.js +10 -0
- package/build/components/DatePicker/time-picker/period-web.d.ts +6 -0
- package/build/components/DatePicker/time-picker/period-web.js +21 -0
- package/build/components/DatePicker/time-picker/wheel-native.d.ts +8 -0
- package/build/components/DatePicker/time-picker/wheel-native.js +19 -0
- package/build/components/DatePicker/time-picker/wheel-picker/index.d.ts +2 -0
- package/build/components/DatePicker/time-picker/wheel-picker/index.js +2 -0
- package/build/components/DatePicker/time-picker/wheel-picker/wheel-picker-item.d.ts +16 -0
- package/build/components/DatePicker/time-picker/wheel-picker/wheel-picker-item.js +97 -0
- package/build/components/DatePicker/time-picker/wheel-picker/wheel-picker.d.ts +21 -0
- package/build/components/DatePicker/time-picker/wheel-picker/wheel-picker.js +88 -0
- package/build/components/DatePicker/time-picker/wheel-picker/wheel-picker.style.d.ts +23 -0
- package/build/components/DatePicker/time-picker/wheel-picker/wheel-picker.style.js +21 -0
- package/build/components/DatePicker/time-picker/wheel-web.d.ts +8 -0
- package/build/components/DatePicker/time-picker/wheel-web.js +146 -0
- package/build/components/DatePicker/time-picker/wheel.d.ts +8 -0
- package/build/components/DatePicker/time-picker/wheel.js +10 -0
- package/build/components/List/List.js +2 -2
- package/build/components/Modal/Modal.js +31 -42
- package/build/components/Modal/Modal.web.js +3 -3
- package/build/components/Pagination/Pagination.d.ts +6 -0
- package/build/components/Pagination/Pagination.js +125 -0
- package/build/components/Pagination/Pagination.props.d.ts +26 -0
- package/build/components/Pagination/Pagination.props.js +1 -0
- package/build/components/Pagination/Pagination.utils.d.ts +2 -0
- package/build/components/Pagination/Pagination.utils.js +20 -0
- package/build/components/Pagination/Pagination.utils.test.d.ts +1 -0
- package/build/components/Pagination/Pagination.utils.test.js +16 -0
- package/build/components/Pagination/index.d.ts +2 -0
- package/build/components/Pagination/index.js +1 -0
- package/build/components/SafeAreaView/SafeAreaView.d.ts +5 -0
- package/build/components/SafeAreaView/SafeAreaView.js +117 -0
- package/build/components/SafeAreaView/SafeAreaView.props.d.ts +17 -0
- package/build/components/SafeAreaView/SafeAreaView.props.js +1 -0
- package/build/components/SafeAreaView/index.d.ts +2 -0
- package/build/components/SafeAreaView/index.js +1 -0
- package/build/components/Select/Select.d.ts +1 -1
- package/build/components/Select/Select.js +6 -5
- package/build/components/Select/Select.props.d.ts +4 -0
- package/build/components/Select/SelectOption.d.ts +1 -1
- package/build/components/Select/SelectOption.js +2 -2
- package/build/components/Table/Table.context.d.ts +12 -0
- package/build/components/Table/Table.context.js +9 -0
- package/build/components/Table/Table.d.ts +6 -0
- package/build/components/Table/Table.js +71 -0
- package/build/components/Table/Table.props.d.ts +56 -0
- package/build/components/Table/Table.props.js +1 -0
- package/build/components/Table/Table.utils.d.ts +5 -0
- package/build/components/Table/Table.utils.js +48 -0
- package/build/components/Table/Table.utils.test.d.ts +1 -0
- package/build/components/Table/Table.utils.test.js +71 -0
- package/build/components/Table/TableBody.d.ts +6 -0
- package/build/components/Table/TableBody.js +16 -0
- package/build/components/Table/TableCell.d.ts +10 -0
- package/build/components/Table/TableCell.js +44 -0
- package/build/components/Table/TableHeader.d.ts +6 -0
- package/build/components/Table/TableHeader.js +24 -0
- package/build/components/Table/TableHeaderCell.d.ts +10 -0
- package/build/components/Table/TableHeaderCell.js +97 -0
- package/build/components/Table/TablePagination.d.ts +6 -0
- package/build/components/Table/TablePagination.js +7 -0
- package/build/components/Table/TableRow.d.ts +8 -0
- package/build/components/Table/TableRow.js +25 -0
- package/build/components/Table/index.d.ts +8 -0
- package/build/components/Table/index.js +7 -0
- package/build/components/Timeline/Timeline.d.ts +6 -0
- package/build/components/Timeline/Timeline.js +34 -0
- package/build/components/Timeline/Timeline.props.d.ts +47 -0
- package/build/components/Timeline/Timeline.props.js +1 -0
- package/build/components/Timeline/TimelineItem.d.ts +6 -0
- package/build/components/Timeline/TimelineItem.js +235 -0
- package/build/components/Timeline/index.d.ts +3 -0
- package/build/components/Timeline/index.js +2 -0
- package/build/components/VerificationInput/VerificationInput.js +3 -3
- package/build/components/index.d.ts +5 -0
- package/build/components/index.js +5 -0
- package/build/tokens/components/dark/timeline.d.ts +2 -2
- package/build/tokens/components/dark/timeline.js +2 -2
- package/docs/components/AllComponents.web.tsx +106 -23
- package/docs/llm-docs/unistyles-llms-full.txt +1132 -534
- package/docs/llm-docs/unistyles-llms-small.txt +37 -37
- package/package.json +4 -4
- package/src/components/Button/Button.stories.tsx +43 -7
- package/src/components/Button/ButtonRoot.tsx +8 -0
- package/src/components/Combobox/Combobox.context.ts +26 -0
- package/src/components/Combobox/Combobox.docs.mdx +277 -0
- package/src/components/Combobox/Combobox.figma.tsx +60 -0
- package/src/components/Combobox/Combobox.props.ts +187 -0
- package/src/components/Combobox/Combobox.stories.tsx +233 -0
- package/src/components/Combobox/Combobox.tsx +446 -0
- package/src/components/Combobox/ComboboxOption.tsx +100 -0
- package/src/components/Combobox/index.ts +9 -0
- package/src/components/List/List.tsx +5 -4
- package/src/components/Modal/Modal.tsx +67 -74
- package/src/components/Modal/Modal.web.tsx +3 -3
- package/src/components/Pagination/Pagination.docs.mdx +99 -0
- package/src/components/Pagination/Pagination.figma.tsx +20 -0
- package/src/components/Pagination/Pagination.props.ts +28 -0
- package/src/components/Pagination/Pagination.stories.tsx +88 -0
- package/src/components/Pagination/Pagination.tsx +248 -0
- package/src/components/Pagination/Pagination.utils.test.ts +20 -0
- package/src/components/Pagination/Pagination.utils.ts +37 -0
- package/src/components/Pagination/index.ts +2 -0
- package/src/components/SafeAreaView/SafeAreaView.props.ts +20 -0
- package/src/components/SafeAreaView/SafeAreaView.tsx +173 -0
- package/src/components/SafeAreaView/index.ts +2 -0
- package/src/components/Select/Select.props.ts +4 -0
- package/src/components/Select/Select.tsx +35 -28
- package/src/components/Select/SelectOption.tsx +2 -0
- package/src/components/Table/Table.context.tsx +23 -0
- package/src/components/Table/Table.docs.mdx +239 -0
- package/src/components/Table/Table.figma.tsx +65 -0
- package/src/components/Table/Table.props.ts +65 -0
- package/src/components/Table/Table.stories.tsx +399 -0
- package/src/components/Table/Table.tsx +127 -0
- package/src/components/Table/Table.utils.test.ts +82 -0
- package/src/components/Table/Table.utils.ts +72 -0
- package/src/components/Table/TableBody.tsx +25 -0
- package/src/components/Table/TableCell.tsx +67 -0
- package/src/components/Table/TableHeader.tsx +41 -0
- package/src/components/Table/TableHeaderCell.tsx +136 -0
- package/src/components/Table/TablePagination.tsx +10 -0
- package/src/components/Table/TableRow.tsx +42 -0
- package/src/components/Table/index.ts +16 -0
- package/src/components/Timeline/Timeline.docs.mdx +177 -0
- package/src/components/Timeline/Timeline.figma.tsx +89 -0
- package/src/components/Timeline/Timeline.props.ts +51 -0
- package/src/components/Timeline/Timeline.stories.tsx +102 -0
- package/src/components/Timeline/Timeline.tsx +48 -0
- package/src/components/Timeline/TimelineItem.tsx +293 -0
- package/src/components/Timeline/index.ts +9 -0
- package/src/components/VerificationInput/VerificationInput.tsx +3 -0
- package/src/components/index.ts +5 -0
- package/src/tokens/components/dark/timeline.ts +2 -2
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { TickSmallIcon } from '@utilitywarehouse/hearth-react-native-icons';
|
|
2
|
+
import { Pressable, View } from 'react-native';
|
|
3
|
+
import { StyleSheet } from 'react-native-unistyles';
|
|
4
|
+
import { BodyText } from '../BodyText';
|
|
5
|
+
import { Icon } from '../Icon';
|
|
6
|
+
import { useComboboxContext } from './Combobox.context';
|
|
7
|
+
import { ComboboxOptionProps } from './Combobox.props';
|
|
8
|
+
|
|
9
|
+
const ComboboxOption = ({
|
|
10
|
+
label,
|
|
11
|
+
value,
|
|
12
|
+
leadingIcon: LeftIcon,
|
|
13
|
+
trailingIcon: RightIcon,
|
|
14
|
+
selected,
|
|
15
|
+
disabled,
|
|
16
|
+
onPress,
|
|
17
|
+
}: ComboboxOptionProps) => {
|
|
18
|
+
const { selectedValue, selectOption } = useComboboxContext();
|
|
19
|
+
const isSelected = selected !== undefined ? selected : selectedValue === value;
|
|
20
|
+
|
|
21
|
+
styles.useVariants({ disabled });
|
|
22
|
+
|
|
23
|
+
const handlePress = () => {
|
|
24
|
+
if (disabled) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (onPress) {
|
|
29
|
+
onPress(value);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
selectOption({ label, value });
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
return (
|
|
37
|
+
<Pressable
|
|
38
|
+
onPress={handlePress}
|
|
39
|
+
disabled={disabled}
|
|
40
|
+
style={({ pressed }) => [styles.container, pressed && styles.pressed]}
|
|
41
|
+
>
|
|
42
|
+
{!!LeftIcon && (
|
|
43
|
+
<View>
|
|
44
|
+
<Icon as={LeftIcon} style={styles.icon} />
|
|
45
|
+
</View>
|
|
46
|
+
)}
|
|
47
|
+
|
|
48
|
+
<View style={styles.labelContainer}>
|
|
49
|
+
<BodyText>{label}</BodyText>
|
|
50
|
+
</View>
|
|
51
|
+
|
|
52
|
+
{isSelected && (
|
|
53
|
+
<View>
|
|
54
|
+
<Icon as={TickSmallIcon} style={styles.icon} />
|
|
55
|
+
</View>
|
|
56
|
+
)}
|
|
57
|
+
{!!RightIcon && !isSelected && (
|
|
58
|
+
<View>
|
|
59
|
+
<Icon as={RightIcon} style={styles.icon} />
|
|
60
|
+
</View>
|
|
61
|
+
)}
|
|
62
|
+
</Pressable>
|
|
63
|
+
);
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
const styles = StyleSheet.create(theme => ({
|
|
67
|
+
container: {
|
|
68
|
+
flexDirection: 'row',
|
|
69
|
+
alignItems: 'center',
|
|
70
|
+
gap: theme.components.select.dropdown.item.gap,
|
|
71
|
+
borderRadius: theme.components.select.dropdown.item.borderRadius,
|
|
72
|
+
paddingVertical: theme.components.select.dropdown.item.padding,
|
|
73
|
+
paddingHorizontal: theme.components.select.dropdown.padding,
|
|
74
|
+
variants: {
|
|
75
|
+
disabled: {
|
|
76
|
+
true: {
|
|
77
|
+
opacity: theme.opacity.disabled,
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
_web: {
|
|
82
|
+
_hover: {
|
|
83
|
+
backgroundColor: theme.color.interactive.functional.surface.subtle.hover,
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
icon: {
|
|
88
|
+
color: theme.color.interactive.functional.foreground.subtle,
|
|
89
|
+
},
|
|
90
|
+
pressed: {
|
|
91
|
+
backgroundColor: theme.color.interactive.functional.surface.subtle.active,
|
|
92
|
+
},
|
|
93
|
+
labelContainer: {
|
|
94
|
+
flex: 1,
|
|
95
|
+
},
|
|
96
|
+
}));
|
|
97
|
+
|
|
98
|
+
ComboboxOption.displayName = 'ComboboxOption';
|
|
99
|
+
|
|
100
|
+
export default ComboboxOption;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { default as Combobox } from './Combobox';
|
|
2
|
+
export { ComboboxContext, useComboboxContext } from './Combobox.context';
|
|
3
|
+
export { default as ComboboxOption } from './ComboboxOption';
|
|
4
|
+
export type {
|
|
5
|
+
default as ComboboxProps,
|
|
6
|
+
ComboboxOptionItemProps,
|
|
7
|
+
ComboboxOptionProps,
|
|
8
|
+
ComboboxRenderContentProps,
|
|
9
|
+
} from './Combobox.props';
|
|
@@ -14,7 +14,8 @@ const List = ({
|
|
|
14
14
|
invalidText,
|
|
15
15
|
...props
|
|
16
16
|
}: ListProps) => {
|
|
17
|
-
const { loading, disabled, container = 'none' } = props;
|
|
17
|
+
const { loading, disabled, container = 'none', testID, style, ...rest } = props;
|
|
18
|
+
|
|
18
19
|
const orderRef = useRef<string[]>([]);
|
|
19
20
|
const [firstItemId, setFirstItemId] = useState<string | undefined>(undefined);
|
|
20
21
|
const containerToCard: {
|
|
@@ -51,7 +52,7 @@ const List = ({
|
|
|
51
52
|
styles.useVariants({ disabled });
|
|
52
53
|
return (
|
|
53
54
|
<ListContext.Provider value={value}>
|
|
54
|
-
<View {...
|
|
55
|
+
<View {...rest} style={[styles.container, style]}>
|
|
55
56
|
{heading ? (
|
|
56
57
|
<SectionHeader
|
|
57
58
|
heading={heading}
|
|
@@ -61,10 +62,10 @@ const List = ({
|
|
|
61
62
|
/>
|
|
62
63
|
) : null}
|
|
63
64
|
{container === 'none' ? (
|
|
64
|
-
<View>{children}</View>
|
|
65
|
+
<View testID={testID}>{children}</View>
|
|
65
66
|
) : (
|
|
66
67
|
React.Children.count(children) > 0 && (
|
|
67
|
-
<Card {...containerToCard} noPadding style={styles.card}>
|
|
68
|
+
<Card {...containerToCard} noPadding style={styles.card} testID={testID}>
|
|
68
69
|
<>{children}</>
|
|
69
70
|
</Card>
|
|
70
71
|
)
|
|
@@ -6,8 +6,8 @@ import {
|
|
|
6
6
|
} from '@gorhom/bottom-sheet';
|
|
7
7
|
import { BottomSheetModalMethods } from '@gorhom/bottom-sheet/lib/typescript/types';
|
|
8
8
|
import { CloseMediumIcon } from '@utilitywarehouse/hearth-react-native-icons';
|
|
9
|
-
import { useCallback, useEffect, useImperativeHandle, useMemo, useRef
|
|
10
|
-
import { AccessibilityInfo,
|
|
9
|
+
import { useCallback, useEffect, useImperativeHandle, useMemo, useRef } from 'react';
|
|
10
|
+
import { AccessibilityInfo, Platform, ScrollView, View, findNodeHandle } from 'react-native';
|
|
11
11
|
import Animated, {
|
|
12
12
|
Easing,
|
|
13
13
|
useAnimatedStyle,
|
|
@@ -22,6 +22,7 @@ import { BodyText } from '../BodyText';
|
|
|
22
22
|
import { BottomSheetModal, BottomSheetScrollView } from '../BottomSheet';
|
|
23
23
|
import { Button } from '../Button';
|
|
24
24
|
import { Heading } from '../Heading';
|
|
25
|
+
import { SafeAreaView } from '../SafeAreaView';
|
|
25
26
|
import { Spinner } from '../Spinner';
|
|
26
27
|
import { UnstyledIconButton } from '../UnstyledIconButton';
|
|
27
28
|
import ModalProps from './Modal.props';
|
|
@@ -62,16 +63,6 @@ const Modal = ({
|
|
|
62
63
|
const pretendContentTranslateY = useSharedValue(20);
|
|
63
64
|
const isBrandBackground = background === 'brand';
|
|
64
65
|
|
|
65
|
-
const [inNavModalHeight, setInNavModalHeight] = useState<number>();
|
|
66
|
-
|
|
67
|
-
const isNavModalFullScreen = useMemo(() => {
|
|
68
|
-
if (!inNavModalHeight || !inNavModal) return false;
|
|
69
|
-
|
|
70
|
-
const screenHeight = Dimensions.get('window').height;
|
|
71
|
-
|
|
72
|
-
return inNavModalHeight >= screenHeight;
|
|
73
|
-
}, [inNavModalHeight, inNavModal]);
|
|
74
|
-
|
|
75
66
|
const triggerCloseAnimation = useCallback(() => {
|
|
76
67
|
if (Platform.OS === 'android' && inNavModal) {
|
|
77
68
|
pretendContentTranslateY.value = withTiming(20, {
|
|
@@ -83,7 +74,7 @@ const Modal = ({
|
|
|
83
74
|
easing: Easing.in(Easing.quad),
|
|
84
75
|
});
|
|
85
76
|
}
|
|
86
|
-
}, [
|
|
77
|
+
}, [inNavModal, pretendContentTranslateY, backgroundOpacity]);
|
|
87
78
|
|
|
88
79
|
useImperativeHandle(ref, () => ({
|
|
89
80
|
...(bottomSheetModalRef.current as BottomSheetModal),
|
|
@@ -150,30 +141,30 @@ const Modal = ({
|
|
|
150
141
|
props.onChange?.(index, position, type);
|
|
151
142
|
};
|
|
152
143
|
|
|
153
|
-
const handleCloseButtonPress = () => {
|
|
144
|
+
const handleCloseButtonPress = useCallback(() => {
|
|
154
145
|
bottomSheetModalRef.current?.dismiss();
|
|
155
146
|
if (onPressCloseButton) {
|
|
156
147
|
onPressCloseButton();
|
|
157
148
|
}
|
|
158
|
-
};
|
|
149
|
+
}, [onPressCloseButton]);
|
|
159
150
|
|
|
160
|
-
const handlePrimaryButtonPress = () => {
|
|
151
|
+
const handlePrimaryButtonPress = useCallback(() => {
|
|
161
152
|
if (onPressPrimaryButton) {
|
|
162
153
|
onPressPrimaryButton();
|
|
163
154
|
}
|
|
164
155
|
if (closeOnPrimaryButtonPress) {
|
|
165
156
|
bottomSheetModalRef.current?.dismiss();
|
|
166
157
|
}
|
|
167
|
-
};
|
|
158
|
+
}, [closeOnPrimaryButtonPress, onPressPrimaryButton]);
|
|
168
159
|
|
|
169
|
-
const handleSecondaryButtonPress = () => {
|
|
160
|
+
const handleSecondaryButtonPress = useCallback(() => {
|
|
170
161
|
if (onPressSecondaryButton) {
|
|
171
162
|
onPressSecondaryButton();
|
|
172
163
|
}
|
|
173
164
|
if (closeOnSecondaryButtonPress) {
|
|
174
165
|
bottomSheetModalRef.current?.dismiss();
|
|
175
166
|
}
|
|
176
|
-
};
|
|
167
|
+
}, [closeOnSecondaryButtonPress, onPressSecondaryButton]);
|
|
177
168
|
|
|
178
169
|
const noButtons = !onPressPrimaryButton && !onPressSecondaryButton;
|
|
179
170
|
|
|
@@ -184,34 +175,45 @@ const Modal = ({
|
|
|
184
175
|
stickyFooter,
|
|
185
176
|
showHandle: props.showHandle,
|
|
186
177
|
background: isBrandBackground ? 'brand' : 'primary',
|
|
187
|
-
...(inNavModal && {
|
|
188
|
-
fullscreen: isNavModalFullScreen,
|
|
189
|
-
}),
|
|
190
178
|
});
|
|
191
179
|
|
|
192
|
-
const footer = (
|
|
193
|
-
|
|
194
|
-
{
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
180
|
+
const footer = useMemo(
|
|
181
|
+
() => (
|
|
182
|
+
<View style={styles.footer}>
|
|
183
|
+
{onPressPrimaryButton && primaryButtonText ? (
|
|
184
|
+
<Button
|
|
185
|
+
onPress={handlePrimaryButtonPress}
|
|
186
|
+
text={primaryButtonText}
|
|
187
|
+
inverted={isBrandBackground && inNavModal}
|
|
188
|
+
{...primaryButtonProps}
|
|
189
|
+
variant={(primaryButtonProps?.variant as 'solid') ?? 'solid'}
|
|
190
|
+
colorScheme={(primaryButtonProps?.colorScheme as 'highlight') ?? 'highlight'}
|
|
191
|
+
/>
|
|
192
|
+
) : null}
|
|
193
|
+
{onPressSecondaryButton && secondaryButtonText ? (
|
|
194
|
+
<Button
|
|
195
|
+
onPress={handleSecondaryButtonPress}
|
|
196
|
+
text={secondaryButtonText}
|
|
197
|
+
inverted={isBrandBackground && inNavModal}
|
|
198
|
+
{...secondaryButtonProps}
|
|
199
|
+
variant={(secondaryButtonProps?.variant as 'outline') ?? 'outline'}
|
|
200
|
+
colorScheme={(secondaryButtonProps?.colorScheme as 'functional') ?? 'functional'}
|
|
201
|
+
/>
|
|
202
|
+
) : null}
|
|
203
|
+
</View>
|
|
204
|
+
),
|
|
205
|
+
[
|
|
206
|
+
handlePrimaryButtonPress,
|
|
207
|
+
handleSecondaryButtonPress,
|
|
208
|
+
inNavModal,
|
|
209
|
+
isBrandBackground,
|
|
210
|
+
onPressPrimaryButton,
|
|
211
|
+
onPressSecondaryButton,
|
|
212
|
+
primaryButtonProps,
|
|
213
|
+
primaryButtonText,
|
|
214
|
+
secondaryButtonProps,
|
|
215
|
+
secondaryButtonText,
|
|
216
|
+
]
|
|
215
217
|
);
|
|
216
218
|
|
|
217
219
|
const InNavModalContainer = scrollable ? ScrollView : View;
|
|
@@ -292,13 +294,23 @@ const Modal = ({
|
|
|
292
294
|
</View>
|
|
293
295
|
) : null}
|
|
294
296
|
{inNavModal && (
|
|
295
|
-
<InNavModalContainer
|
|
297
|
+
<InNavModalContainer
|
|
298
|
+
style={{
|
|
299
|
+
flex: stickyFooter ? 1 : 0,
|
|
300
|
+
...(scrollable ? { marginHorizontal: -1 } : {}),
|
|
301
|
+
}}
|
|
302
|
+
{...(scrollable ? { contentContainerStyle: { paddingHorizontal: 1 } } : {})}
|
|
303
|
+
>
|
|
296
304
|
{children}
|
|
297
|
-
{!stickyFooter ?
|
|
305
|
+
{!stickyFooter ? (
|
|
306
|
+
<View style={styles.inNavModalFooterContainer}>{footer}</View>
|
|
307
|
+
) : null}
|
|
298
308
|
</InNavModalContainer>
|
|
299
309
|
)}
|
|
300
310
|
{!inNavModal && children}
|
|
301
|
-
{((!stickyFooter && !inNavModal) || (inNavModal && stickyFooter)) && !noButtons
|
|
311
|
+
{((!stickyFooter && !inNavModal) || (inNavModal && stickyFooter)) && !noButtons
|
|
312
|
+
? footer
|
|
313
|
+
: null}
|
|
302
314
|
</View>
|
|
303
315
|
)}
|
|
304
316
|
</>
|
|
@@ -310,21 +322,11 @@ const Modal = ({
|
|
|
310
322
|
<View style={styles.footerWrap}>{footer}</View>
|
|
311
323
|
</BottomSheetFooter>
|
|
312
324
|
),
|
|
313
|
-
[
|
|
314
|
-
onPressPrimaryButton,
|
|
315
|
-
primaryButtonText,
|
|
316
|
-
onPressSecondaryButton,
|
|
317
|
-
secondaryButtonText,
|
|
318
|
-
primaryButtonProps,
|
|
319
|
-
secondaryButtonProps,
|
|
320
|
-
]
|
|
325
|
+
[footer]
|
|
321
326
|
);
|
|
322
327
|
|
|
323
328
|
return inNavModal ? (
|
|
324
329
|
<View
|
|
325
|
-
onLayout={(e) => {
|
|
326
|
-
setInNavModalHeight(e.nativeEvent.layout.height);
|
|
327
|
-
}}
|
|
328
330
|
style={{
|
|
329
331
|
flex: 1,
|
|
330
332
|
backgroundColor: theme.color.background[isBrandBackground ? 'brand' : 'primary'],
|
|
@@ -338,9 +340,9 @@ const Modal = ({
|
|
|
338
340
|
<Animated.View
|
|
339
341
|
style={[styles.inNavModalContainer, Platform.OS === 'android' && animatedInNavModalStyle]}
|
|
340
342
|
>
|
|
341
|
-
<
|
|
343
|
+
<SafeAreaView edges={['top', 'bottom']} style={styles.inNavModalContent}>
|
|
342
344
|
{content}
|
|
343
|
-
</
|
|
345
|
+
</SafeAreaView>
|
|
344
346
|
</Animated.View>
|
|
345
347
|
</View>
|
|
346
348
|
) : (
|
|
@@ -471,7 +473,7 @@ const styles = StyleSheet.create((theme, rt) => ({
|
|
|
471
473
|
borderTopLeftRadius: theme.components.modal.borderRadius,
|
|
472
474
|
borderTopRightRadius: theme.components.modal.borderRadius,
|
|
473
475
|
backgroundColor: theme.color.surface.neutral.strong,
|
|
474
|
-
|
|
476
|
+
padding: theme.components.bottomSheet.padding,
|
|
475
477
|
variants: {
|
|
476
478
|
background: {
|
|
477
479
|
primary: {},
|
|
@@ -479,24 +481,15 @@ const styles = StyleSheet.create((theme, rt) => ({
|
|
|
479
481
|
backgroundColor: theme.color.background.brand,
|
|
480
482
|
},
|
|
481
483
|
},
|
|
482
|
-
fullscreen: {
|
|
483
|
-
true: {
|
|
484
|
-
padding: theme.components.modal.padding,
|
|
485
|
-
paddingTop: rt.insets.top,
|
|
486
|
-
},
|
|
487
|
-
false: {
|
|
488
|
-
padding: theme.components.modal.padding,
|
|
489
|
-
}
|
|
490
|
-
}
|
|
491
484
|
},
|
|
492
485
|
},
|
|
493
486
|
inNavModalFooterContainer: {
|
|
494
|
-
paddingTop: theme.components.
|
|
487
|
+
paddingTop: theme.components.bottomSheet.padding,
|
|
495
488
|
},
|
|
496
489
|
androidContainer: {
|
|
497
490
|
height: rt.insets.top + 18,
|
|
498
|
-
paddingLeft: theme.components.
|
|
499
|
-
paddingRight: theme.components.
|
|
491
|
+
paddingLeft: theme.components.bottomSheet.padding,
|
|
492
|
+
paddingRight: theme.components.bottomSheet.padding,
|
|
500
493
|
justifyContent: 'flex-end',
|
|
501
494
|
},
|
|
502
495
|
pretendContent: {
|
|
@@ -310,13 +310,13 @@ const styles = StyleSheet.create((theme, rt) => ({
|
|
|
310
310
|
borderTopRightRadius: theme.components.modal.borderRadius,
|
|
311
311
|
backgroundColor: theme.color.surface.neutral.strong,
|
|
312
312
|
gap: theme.components.modal.gap,
|
|
313
|
-
padding: theme.components.
|
|
313
|
+
padding: theme.components.bottomSheet.padding,
|
|
314
314
|
paddingBottom: theme.components.modal.padding + rt.insets.bottom,
|
|
315
315
|
},
|
|
316
316
|
androidContainer: {
|
|
317
317
|
height: rt.insets.top + 18,
|
|
318
|
-
paddingLeft: theme.components.
|
|
319
|
-
paddingRight: theme.components.
|
|
318
|
+
paddingLeft: theme.components.bottomSheet.padding,
|
|
319
|
+
paddingRight: theme.components.bottomSheet.padding,
|
|
320
320
|
justifyContent: 'flex-end',
|
|
321
321
|
},
|
|
322
322
|
pretendContent: {
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { Canvas, Controls, Meta } from '@storybook/addon-docs/blocks';
|
|
2
|
+
import { Box, Center, Pagination } from '../..';
|
|
3
|
+
import { BackToTopButton, UsageWrap, ViewFigmaButton } from '../../../docs/components';
|
|
4
|
+
import * as Stories from './Pagination.stories';
|
|
5
|
+
|
|
6
|
+
<Meta title="Components / Pagination" />
|
|
7
|
+
|
|
8
|
+
<BackToTopButton />
|
|
9
|
+
|
|
10
|
+
<ViewFigmaButton url="https://www.figma.com/design/6NKZXZhFSExXrcbBgc6zTR/Hearth-Components---Tokens?node-id=6416-5836&t=pZwKJYFo1y1QRQD1-4" />
|
|
11
|
+
|
|
12
|
+
# Pagination
|
|
13
|
+
|
|
14
|
+
Pagination helps users move between pages of content while keeping the current position visible. It supports both a full page list and a condensed “Page X of Y” layout.
|
|
15
|
+
|
|
16
|
+
- [Playground](#playground)
|
|
17
|
+
- [Usage](#usage)
|
|
18
|
+
- [Props](#props)
|
|
19
|
+
- [Examples](#examples)
|
|
20
|
+
|
|
21
|
+
## Playground
|
|
22
|
+
|
|
23
|
+
<Canvas of={Stories.Playground} />
|
|
24
|
+
|
|
25
|
+
<Controls of={Stories.Playground} />
|
|
26
|
+
|
|
27
|
+
## Usage
|
|
28
|
+
|
|
29
|
+
<UsageWrap>
|
|
30
|
+
<Center>
|
|
31
|
+
<Box style={{ width: 520, maxWidth: '100%' }}>
|
|
32
|
+
<Pagination currentPage={3} totalPages={10} onPageChange={() => {}} />
|
|
33
|
+
</Box>
|
|
34
|
+
</Center>
|
|
35
|
+
</UsageWrap>
|
|
36
|
+
|
|
37
|
+
```tsx
|
|
38
|
+
import { Pagination } from '@utilitywarehouse/hearth-react-native';
|
|
39
|
+
import { useState } from 'react';
|
|
40
|
+
|
|
41
|
+
const MyComponent = () => {
|
|
42
|
+
const [page, setPage] = useState(3);
|
|
43
|
+
|
|
44
|
+
return <Pagination currentPage={page} totalPages={10} onPageChange={setPage} />;
|
|
45
|
+
};
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Props
|
|
49
|
+
|
|
50
|
+
| Property | Type | Description | Default |
|
|
51
|
+
| ----------------- | ------------------------ | ------------------------------------------------- | -------- |
|
|
52
|
+
| `currentPage` | `number` | The current active page number. | Required |
|
|
53
|
+
| `totalPages` | `number` | Total number of pages available. | Required |
|
|
54
|
+
| `onPageChange` | `(page: number) => void` | Called when the user selects a different page. | Required |
|
|
55
|
+
| `condensed` | `boolean` | Displays “Page X of Y” instead of numbered items. | `false` |
|
|
56
|
+
| `hideSkipButtons` | `boolean` | Hides the first and last page controls. | `false` |
|
|
57
|
+
|
|
58
|
+
## Examples
|
|
59
|
+
|
|
60
|
+
### Condensed
|
|
61
|
+
|
|
62
|
+
<Canvas of={Stories.Condensed} />
|
|
63
|
+
|
|
64
|
+
```tsx
|
|
65
|
+
const [currentPage, setCurrentPage] = useState(1);
|
|
66
|
+
|
|
67
|
+
<Pagination condensed currentPage={currentPage} onPageChange={setCurrentPage} totalPages={10} />;
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Without skip buttons
|
|
71
|
+
|
|
72
|
+
<Canvas of={Stories.WithoutSkipButtons} />
|
|
73
|
+
|
|
74
|
+
```tsx
|
|
75
|
+
const [currentPage, setCurrentPage] = useState(3);
|
|
76
|
+
|
|
77
|
+
<Pagination
|
|
78
|
+
currentPage={currentPage}
|
|
79
|
+
hideSkipButtons
|
|
80
|
+
onPageChange={setCurrentPage}
|
|
81
|
+
totalPages={10}
|
|
82
|
+
/>;
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Edge cases
|
|
86
|
+
|
|
87
|
+
<Canvas of={Stories.EdgeCases} />
|
|
88
|
+
|
|
89
|
+
```tsx
|
|
90
|
+
const [nearStartPage, setNearStartPage] = useState(2);
|
|
91
|
+
const [middlePage, setMiddlePage] = useState(5);
|
|
92
|
+
const [nearEndPage, setNearEndPage] = useState(9);
|
|
93
|
+
|
|
94
|
+
<Flex direction="column" spacing="lg" style={{ width: '100%', maxWidth: 520 }}>
|
|
95
|
+
<Pagination currentPage={nearStartPage} onPageChange={setNearStartPage} totalPages={10} />
|
|
96
|
+
<Pagination currentPage={middlePage} onPageChange={setMiddlePage} totalPages={10} />
|
|
97
|
+
<Pagination currentPage={nearEndPage} onPageChange={setNearEndPage} totalPages={10} />
|
|
98
|
+
</Flex>;
|
|
99
|
+
```
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import figma from '@figma/code-connect';
|
|
2
|
+
import { Pagination } from './';
|
|
3
|
+
|
|
4
|
+
figma.connect(
|
|
5
|
+
Pagination,
|
|
6
|
+
'https://www.figma.com/design/6NKZXZhFSExXrcbBgc6zTR/Hearth-Components---Tokens?node-id=6416-5836&t=pZwKJYFo1y1QRQD1-4',
|
|
7
|
+
{
|
|
8
|
+
props: {
|
|
9
|
+
condensed: figma.boolean('Condensed?'),
|
|
10
|
+
},
|
|
11
|
+
example: props => (
|
|
12
|
+
<Pagination
|
|
13
|
+
currentPage={1}
|
|
14
|
+
totalPages={10}
|
|
15
|
+
onPageChange={() => {}}
|
|
16
|
+
condensed={props.condensed}
|
|
17
|
+
/>
|
|
18
|
+
),
|
|
19
|
+
}
|
|
20
|
+
);
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { ViewProps } from 'react-native';
|
|
2
|
+
|
|
3
|
+
export interface PaginationProps extends ViewProps {
|
|
4
|
+
/**
|
|
5
|
+
* The current active page number (1-indexed).
|
|
6
|
+
*/
|
|
7
|
+
currentPage: number;
|
|
8
|
+
/**
|
|
9
|
+
* The total number of pages.
|
|
10
|
+
*/
|
|
11
|
+
totalPages: number;
|
|
12
|
+
/**
|
|
13
|
+
* Callback fired when the page changes.
|
|
14
|
+
*/
|
|
15
|
+
onPageChange: (page: number) => void;
|
|
16
|
+
/**
|
|
17
|
+
* Whether to show condensed copy instead of individual page items.
|
|
18
|
+
* @default false
|
|
19
|
+
*/
|
|
20
|
+
condensed?: boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Whether to hide the first and last page controls.
|
|
23
|
+
* @default false
|
|
24
|
+
*/
|
|
25
|
+
hideSkipButtons?: boolean;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export default PaginationProps;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { Meta, StoryObj } from '@storybook/react-native';
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
import { BodyText } from '../BodyText';
|
|
4
|
+
import { Flex } from '../Flex';
|
|
5
|
+
import { Pagination } from './';
|
|
6
|
+
|
|
7
|
+
const meta = {
|
|
8
|
+
title: 'Stories / Pagination',
|
|
9
|
+
component: Pagination,
|
|
10
|
+
args: {
|
|
11
|
+
currentPage: 1,
|
|
12
|
+
totalPages: 10,
|
|
13
|
+
condensed: false,
|
|
14
|
+
hideSkipButtons: false,
|
|
15
|
+
},
|
|
16
|
+
argTypes: {
|
|
17
|
+
currentPage: { control: { type: 'number', min: 1 } },
|
|
18
|
+
totalPages: { control: { type: 'number', min: 1 } },
|
|
19
|
+
condensed: { control: 'boolean' },
|
|
20
|
+
hideSkipButtons: { control: 'boolean' },
|
|
21
|
+
},
|
|
22
|
+
} satisfies Meta<typeof Pagination>;
|
|
23
|
+
|
|
24
|
+
export default meta;
|
|
25
|
+
type Story = StoryObj<typeof meta>;
|
|
26
|
+
|
|
27
|
+
export const Playground: Story = {
|
|
28
|
+
render: (args: StoryObj<typeof meta.args>) => {
|
|
29
|
+
const [currentPage, setCurrentPage] = useState(args.currentPage);
|
|
30
|
+
|
|
31
|
+
return <Pagination {...args} currentPage={currentPage} onPageChange={setCurrentPage} />;
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export const Condensed: Story = {
|
|
36
|
+
render: () => {
|
|
37
|
+
const [currentPage, setCurrentPage] = useState(1);
|
|
38
|
+
|
|
39
|
+
return (
|
|
40
|
+
<Pagination
|
|
41
|
+
condensed
|
|
42
|
+
currentPage={currentPage}
|
|
43
|
+
onPageChange={setCurrentPage}
|
|
44
|
+
totalPages={10}
|
|
45
|
+
/>
|
|
46
|
+
);
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export const WithoutSkipButtons: Story = {
|
|
51
|
+
render: () => {
|
|
52
|
+
const [currentPage, setCurrentPage] = useState(3);
|
|
53
|
+
|
|
54
|
+
return (
|
|
55
|
+
<Pagination
|
|
56
|
+
currentPage={currentPage}
|
|
57
|
+
hideSkipButtons
|
|
58
|
+
onPageChange={setCurrentPage}
|
|
59
|
+
totalPages={10}
|
|
60
|
+
/>
|
|
61
|
+
);
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export const EdgeCases: Story = {
|
|
66
|
+
render: () => {
|
|
67
|
+
const [nearStartPage, setNearStartPage] = useState(2);
|
|
68
|
+
const [middlePage, setMiddlePage] = useState(5);
|
|
69
|
+
const [nearEndPage, setNearEndPage] = useState(9);
|
|
70
|
+
|
|
71
|
+
return (
|
|
72
|
+
<Flex direction="column" spacing="lg" style={{ width: '100%', maxWidth: 520 }}>
|
|
73
|
+
<Flex direction="column" spacing="xs">
|
|
74
|
+
<BodyText size="sm">Near start</BodyText>
|
|
75
|
+
<Pagination currentPage={nearStartPage} onPageChange={setNearStartPage} totalPages={10} />
|
|
76
|
+
</Flex>
|
|
77
|
+
<Flex direction="column" spacing="xs">
|
|
78
|
+
<BodyText size="sm">Middle</BodyText>
|
|
79
|
+
<Pagination currentPage={middlePage} onPageChange={setMiddlePage} totalPages={10} />
|
|
80
|
+
</Flex>
|
|
81
|
+
<Flex direction="column" spacing="xs">
|
|
82
|
+
<BodyText size="sm">Near end</BodyText>
|
|
83
|
+
<Pagination currentPage={nearEndPage} onPageChange={setNearEndPage} totalPages={10} />
|
|
84
|
+
</Flex>
|
|
85
|
+
</Flex>
|
|
86
|
+
);
|
|
87
|
+
},
|
|
88
|
+
};
|