@boostdev/design-system-components 2.4.2 → 2.5.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/AGENTS.md +4 -20
- package/README.md +3 -23
- package/dist/client.cjs +115 -61
- package/dist/client.css +537 -537
- package/dist/client.d.cts +11 -1
- package/dist/client.d.ts +11 -1
- package/dist/client.js +115 -61
- package/dist/index.cjs +115 -61
- package/dist/index.css +537 -537
- package/dist/index.d.cts +11 -1
- package/dist/index.d.ts +11 -1
- package/dist/index.js +115 -61
- package/dist/web-components/index.js +23 -3
- package/package.json +2 -10
- package/src/components/layout/Grid/Grid.mdx +20 -2
- package/src/components/layout/Grid/Grid.spec.tsx +194 -4
- package/src/components/layout/Grid/Grid.tsx +15 -1
- package/src/components/layout/Grid/masonry.ts +127 -9
- package/dist/native/index.cjs +0 -4337
- package/dist/native/index.d.cts +0 -574
- package/dist/native/index.d.ts +0 -574
- package/dist/native/index.js +0 -4421
- package/src/components/interaction/Button/Button.native.mdx +0 -91
- package/src/components/interaction/Button/Button.native.spec.tsx +0 -55
- package/src/components/interaction/Button/Button.native.stories.tsx +0 -141
- package/src/components/interaction/Button/Button.native.tsx +0 -105
- package/src/components/interaction/Dialog/Dialog.native.mdx +0 -61
- package/src/components/interaction/Dialog/Dialog.native.spec.tsx +0 -73
- package/src/components/interaction/Dialog/Dialog.native.stories.tsx +0 -53
- package/src/components/interaction/Dialog/Dialog.native.tsx +0 -128
- package/src/components/interaction/Drawer/Drawer.native.mdx +0 -58
- package/src/components/interaction/Drawer/Drawer.native.spec.tsx +0 -81
- package/src/components/interaction/Drawer/Drawer.native.stories.tsx +0 -33
- package/src/components/interaction/Drawer/Drawer.native.tsx +0 -175
- package/src/components/interaction/DropdownMenu/DropdownMenu.native.mdx +0 -74
- package/src/components/interaction/DropdownMenu/DropdownMenu.native.spec.tsx +0 -78
- package/src/components/interaction/DropdownMenu/DropdownMenu.native.stories.tsx +0 -51
- package/src/components/interaction/DropdownMenu/DropdownMenu.native.tsx +0 -254
- package/src/components/interaction/Popover/Popover.native.mdx +0 -61
- package/src/components/interaction/Popover/Popover.native.spec.tsx +0 -73
- package/src/components/interaction/Popover/Popover.native.stories.tsx +0 -44
- package/src/components/interaction/Popover/Popover.native.tsx +0 -87
- package/src/components/interaction/Rating/Rating.native.mdx +0 -55
- package/src/components/interaction/Rating/Rating.native.spec.tsx +0 -38
- package/src/components/interaction/Rating/Rating.native.stories.tsx +0 -37
- package/src/components/interaction/Rating/Rating.native.tsx +0 -50
- package/src/components/interaction/Toast/Toast.native.mdx +0 -81
- package/src/components/interaction/Toast/Toast.native.spec.tsx +0 -80
- package/src/components/interaction/Toast/Toast.native.stories.tsx +0 -47
- package/src/components/interaction/Toast/Toast.native.tsx +0 -202
- package/src/components/interaction/form/Checkbox/Checkbox.native.mdx +0 -74
- package/src/components/interaction/form/Checkbox/Checkbox.native.spec.tsx +0 -42
- package/src/components/interaction/form/Checkbox/Checkbox.native.stories.tsx +0 -34
- package/src/components/interaction/form/Checkbox/Checkbox.native.tsx +0 -80
- package/src/components/interaction/form/CheckboxGroup/CheckboxGroup.native.mdx +0 -78
- package/src/components/interaction/form/CheckboxGroup/CheckboxGroup.native.spec.tsx +0 -57
- package/src/components/interaction/form/CheckboxGroup/CheckboxGroup.native.stories.tsx +0 -96
- package/src/components/interaction/form/CheckboxGroup/CheckboxGroup.native.tsx +0 -61
- package/src/components/interaction/form/Combobox/Combobox.native.mdx +0 -86
- package/src/components/interaction/form/Combobox/Combobox.native.spec.tsx +0 -60
- package/src/components/interaction/form/Combobox/Combobox.native.stories.tsx +0 -99
- package/src/components/interaction/form/Combobox/Combobox.native.tsx +0 -211
- package/src/components/interaction/form/FileInput/FileInput.native.mdx +0 -86
- package/src/components/interaction/form/FileInput/FileInput.native.spec.tsx +0 -73
- package/src/components/interaction/form/FileInput/FileInput.native.stories.tsx +0 -69
- package/src/components/interaction/form/FileInput/FileInput.native.tsx +0 -129
- package/src/components/interaction/form/FormInput/FormInput.native.mdx +0 -81
- package/src/components/interaction/form/FormInput/FormInput.native.spec.tsx +0 -51
- package/src/components/interaction/form/FormInput/FormInput.native.stories.tsx +0 -54
- package/src/components/interaction/form/FormInput/FormInput.native.tsx +0 -122
- package/src/components/interaction/form/NumberInput/NumberInput.native.mdx +0 -87
- package/src/components/interaction/form/NumberInput/NumberInput.native.spec.tsx +0 -63
- package/src/components/interaction/form/NumberInput/NumberInput.native.stories.tsx +0 -63
- package/src/components/interaction/form/NumberInput/NumberInput.native.tsx +0 -198
- package/src/components/interaction/form/Radio/Radio.native.spec.tsx +0 -79
- package/src/components/interaction/form/Radio/Radio.native.stories.tsx +0 -44
- package/src/components/interaction/form/Radio/Radio.native.tsx +0 -79
- package/src/components/interaction/form/RadioGroup/RadioGroup.native.mdx +0 -79
- package/src/components/interaction/form/RadioGroup/RadioGroup.native.spec.tsx +0 -66
- package/src/components/interaction/form/RadioGroup/RadioGroup.native.stories.tsx +0 -96
- package/src/components/interaction/form/RadioGroup/RadioGroup.native.tsx +0 -61
- package/src/components/interaction/form/SegmentedControl/SegmentedControl.native.mdx +0 -78
- package/src/components/interaction/form/SegmentedControl/SegmentedControl.native.spec.tsx +0 -82
- package/src/components/interaction/form/SegmentedControl/SegmentedControl.native.stories.tsx +0 -99
- package/src/components/interaction/form/SegmentedControl/SegmentedControl.native.tsx +0 -121
- package/src/components/interaction/form/Select/Select.native.mdx +0 -85
- package/src/components/interaction/form/Select/Select.native.spec.tsx +0 -64
- package/src/components/interaction/form/Select/Select.native.stories.tsx +0 -75
- package/src/components/interaction/form/Select/Select.native.tsx +0 -252
- package/src/components/interaction/form/Slider/Slider.native.mdx +0 -83
- package/src/components/interaction/form/Slider/Slider.native.spec.tsx +0 -51
- package/src/components/interaction/form/Slider/Slider.native.stories.tsx +0 -58
- package/src/components/interaction/form/Slider/Slider.native.tsx +0 -188
- package/src/components/interaction/form/Switch/Switch.native.spec.tsx +0 -60
- package/src/components/interaction/form/Switch/Switch.native.stories.tsx +0 -33
- package/src/components/interaction/form/Switch/Switch.native.tsx +0 -59
- package/src/components/interaction/form/Textarea/Textarea.native.mdx +0 -76
- package/src/components/interaction/form/Textarea/Textarea.native.spec.tsx +0 -50
- package/src/components/interaction/form/Textarea/Textarea.native.stories.tsx +0 -50
- package/src/components/interaction/form/Textarea/Textarea.native.tsx +0 -108
- package/src/components/interaction/form/atoms/Label.native.spec.tsx +0 -39
- package/src/components/interaction/form/atoms/Label.native.stories.tsx +0 -18
- package/src/components/interaction/form/atoms/Label.native.tsx +0 -29
- package/src/components/interaction/form/atoms/Message.native.spec.tsx +0 -30
- package/src/components/interaction/form/atoms/Message.native.stories.tsx +0 -22
- package/src/components/interaction/form/atoms/Message.native.tsx +0 -34
- package/src/components/layout/ButtonGroup/ButtonGroup.native.spec.tsx +0 -83
- package/src/components/layout/ButtonGroup/ButtonGroup.native.stories.tsx +0 -44
- package/src/components/layout/ButtonGroup/ButtonGroup.native.tsx +0 -44
- package/src/components/layout/Card/Card.native.spec.tsx +0 -102
- package/src/components/layout/Card/Card.native.stories.tsx +0 -51
- package/src/components/layout/Card/Card.native.tsx +0 -89
- package/src/components/layout/IconWrapper/IconWrapper.native.spec.tsx +0 -39
- package/src/components/layout/IconWrapper/IconWrapper.native.stories.tsx +0 -37
- package/src/components/layout/IconWrapper/IconWrapper.native.tsx +0 -20
- package/src/components/layout/SectionHeader/SectionHeader.native.spec.tsx +0 -51
- package/src/components/layout/SectionHeader/SectionHeader.native.stories.tsx +0 -36
- package/src/components/layout/SectionHeader/SectionHeader.native.tsx +0 -79
- package/src/components/ui/Accordion/Accordion.native.mdx +0 -65
- package/src/components/ui/Accordion/Accordion.native.spec.tsx +0 -69
- package/src/components/ui/Accordion/Accordion.native.stories.tsx +0 -52
- package/src/components/ui/Accordion/Accordion.native.tsx +0 -141
- package/src/components/ui/Alert/Alert.native.mdx +0 -62
- package/src/components/ui/Alert/Alert.native.spec.tsx +0 -76
- package/src/components/ui/Alert/Alert.native.stories.tsx +0 -41
- package/src/components/ui/Alert/Alert.native.tsx +0 -94
- package/src/components/ui/Avatar/Avatar.native.mdx +0 -50
- package/src/components/ui/Avatar/Avatar.native.spec.tsx +0 -47
- package/src/components/ui/Avatar/Avatar.native.stories.tsx +0 -32
- package/src/components/ui/Avatar/Avatar.native.tsx +0 -85
- package/src/components/ui/Badge/Badge.native.mdx +0 -54
- package/src/components/ui/Badge/Badge.native.spec.tsx +0 -45
- package/src/components/ui/Badge/Badge.native.stories.tsx +0 -34
- package/src/components/ui/Badge/Badge.native.tsx +0 -50
- package/src/components/ui/Breadcrumb/Breadcrumb.native.mdx +0 -52
- package/src/components/ui/Breadcrumb/Breadcrumb.native.spec.tsx +0 -49
- package/src/components/ui/Breadcrumb/Breadcrumb.native.stories.tsx +0 -46
- package/src/components/ui/Breadcrumb/Breadcrumb.native.tsx +0 -83
- package/src/components/ui/Calendar/Calendar.native.mdx +0 -58
- package/src/components/ui/Calendar/Calendar.native.spec.tsx +0 -92
- package/src/components/ui/Calendar/Calendar.native.stories.tsx +0 -45
- package/src/components/ui/Calendar/Calendar.native.tsx +0 -294
- package/src/components/ui/Carousel/Carousel.native.mdx +0 -55
- package/src/components/ui/Carousel/Carousel.native.spec.tsx +0 -55
- package/src/components/ui/Carousel/Carousel.native.stories.tsx +0 -59
- package/src/components/ui/Carousel/Carousel.native.tsx +0 -184
- package/src/components/ui/Collapsible/Collapsible.native.mdx +0 -53
- package/src/components/ui/Collapsible/Collapsible.native.spec.tsx +0 -68
- package/src/components/ui/Collapsible/Collapsible.native.stories.tsx +0 -48
- package/src/components/ui/Collapsible/Collapsible.native.tsx +0 -139
- package/src/components/ui/DescriptionList/DescriptionList.native.mdx +0 -50
- package/src/components/ui/DescriptionList/DescriptionList.native.spec.tsx +0 -37
- package/src/components/ui/DescriptionList/DescriptionList.native.stories.tsx +0 -48
- package/src/components/ui/DescriptionList/DescriptionList.native.tsx +0 -54
- package/src/components/ui/Link/Link.native.mdx +0 -53
- package/src/components/ui/Link/Link.native.spec.tsx +0 -35
- package/src/components/ui/Link/Link.native.stories.tsx +0 -46
- package/src/components/ui/Link/Link.native.tsx +0 -48
- package/src/components/ui/Loading/Loading.native.spec.tsx +0 -24
- package/src/components/ui/Loading/Loading.native.stories.tsx +0 -31
- package/src/components/ui/Loading/Loading.native.tsx +0 -29
- package/src/components/ui/NotificationBanner/NotificationBanner.native.spec.tsx +0 -85
- package/src/components/ui/NotificationBanner/NotificationBanner.native.stories.tsx +0 -37
- package/src/components/ui/NotificationBanner/NotificationBanner.native.tsx +0 -76
- package/src/components/ui/Pagination/Pagination.native.mdx +0 -62
- package/src/components/ui/Pagination/Pagination.native.spec.tsx +0 -86
- package/src/components/ui/Pagination/Pagination.native.stories.tsx +0 -47
- package/src/components/ui/Pagination/Pagination.native.tsx +0 -157
- package/src/components/ui/Progress/Progress.native.spec.tsx +0 -56
- package/src/components/ui/Progress/Progress.native.stories.tsx +0 -34
- package/src/components/ui/Progress/Progress.native.tsx +0 -84
- package/src/components/ui/ProgressCircle/ProgressCircle.native.mdx +0 -63
- package/src/components/ui/ProgressCircle/ProgressCircle.native.spec.tsx +0 -39
- package/src/components/ui/ProgressCircle/ProgressCircle.native.stories.tsx +0 -36
- package/src/components/ui/ProgressCircle/ProgressCircle.native.tsx +0 -176
- package/src/components/ui/Separator/Separator.native.spec.tsx +0 -39
- package/src/components/ui/Separator/Separator.native.stories.tsx +0 -38
- package/src/components/ui/Separator/Separator.native.tsx +0 -32
- package/src/components/ui/Skeleton/Skeleton.native.spec.tsx +0 -39
- package/src/components/ui/Skeleton/Skeleton.native.stories.tsx +0 -31
- package/src/components/ui/Skeleton/Skeleton.native.tsx +0 -42
- package/src/components/ui/Table/Table.native.mdx +0 -72
- package/src/components/ui/Table/Table.native.spec.tsx +0 -83
- package/src/components/ui/Table/Table.native.stories.tsx +0 -55
- package/src/components/ui/Table/Table.native.tsx +0 -196
- package/src/components/ui/Tabs/Tabs.native.mdx +0 -65
- package/src/components/ui/Tabs/Tabs.native.spec.tsx +0 -65
- package/src/components/ui/Tabs/Tabs.native.stories.tsx +0 -57
- package/src/components/ui/Tabs/Tabs.native.tsx +0 -133
- package/src/components/ui/Tooltip/Tooltip.native.mdx +0 -47
- package/src/components/ui/Tooltip/Tooltip.native.spec.tsx +0 -37
- package/src/components/ui/Tooltip/Tooltip.native.stories.tsx +0 -38
- package/src/components/ui/Tooltip/Tooltip.native.tsx +0 -57
- package/src/components/ui/Typography/Typography.native.mdx +0 -56
- package/src/components/ui/Typography/Typography.native.spec.tsx +0 -49
- package/src/components/ui/Typography/Typography.native.stories.tsx +0 -36
- package/src/components/ui/Typography/Typography.native.tsx +0 -65
- package/src/native/ThemeContext.tsx +0 -28
- package/src/native/tokens.ts +0 -13
- package/src/native.ts +0 -76
- package/src/stories/ReactNative.mdx +0 -156
|
@@ -1,254 +0,0 @@
|
|
|
1
|
-
import React, { ReactElement, ReactNode, useState, useEffect, useRef } from 'react';
|
|
2
|
-
import {
|
|
3
|
-
Modal,
|
|
4
|
-
View,
|
|
5
|
-
Pressable,
|
|
6
|
-
Text,
|
|
7
|
-
FlatList,
|
|
8
|
-
Animated,
|
|
9
|
-
StyleSheet,
|
|
10
|
-
Dimensions,
|
|
11
|
-
SafeAreaView,
|
|
12
|
-
StyleProp,
|
|
13
|
-
ViewStyle,
|
|
14
|
-
} from 'react-native';
|
|
15
|
-
import { spacing, font, border, lineHeight } from '../../../native/tokens';
|
|
16
|
-
import { useTheme } from '../../../native/ThemeContext';
|
|
17
|
-
|
|
18
|
-
export interface DropdownMenuItem {
|
|
19
|
-
id: string;
|
|
20
|
-
label: string;
|
|
21
|
-
onPress?: () => void;
|
|
22
|
-
disabled?: boolean;
|
|
23
|
-
icon?: ReactNode;
|
|
24
|
-
separator?: boolean;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
interface DropdownMenuProps {
|
|
28
|
-
trigger: ReactElement;
|
|
29
|
-
items: DropdownMenuItem[];
|
|
30
|
-
title?: string;
|
|
31
|
-
style?: StyleProp<ViewStyle>;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
const styles = StyleSheet.create({
|
|
35
|
-
overlay: {
|
|
36
|
-
flex: 1,
|
|
37
|
-
justifyContent: 'flex-end',
|
|
38
|
-
},
|
|
39
|
-
sheet: {
|
|
40
|
-
maxHeight: '60%',
|
|
41
|
-
borderTopStartRadius: border.radius.m,
|
|
42
|
-
borderTopEndRadius: border.radius.m,
|
|
43
|
-
paddingTop: spacing.m,
|
|
44
|
-
paddingBottom: spacing.xxxl,
|
|
45
|
-
},
|
|
46
|
-
sheetHeader: {
|
|
47
|
-
flexDirection: 'row',
|
|
48
|
-
justifyContent: 'space-between',
|
|
49
|
-
alignItems: 'center',
|
|
50
|
-
paddingHorizontal: spacing.m,
|
|
51
|
-
paddingBottom: spacing.s,
|
|
52
|
-
borderBottomWidth: 1,
|
|
53
|
-
marginBottom: spacing.xxs,
|
|
54
|
-
},
|
|
55
|
-
sheetTitle: {
|
|
56
|
-
fontFamily: font.family.body,
|
|
57
|
-
fontSize: font.size.heading3,
|
|
58
|
-
fontWeight: font.weight.semibold,
|
|
59
|
-
},
|
|
60
|
-
closeText: {
|
|
61
|
-
fontFamily: font.family.body,
|
|
62
|
-
fontSize: font.size.body,
|
|
63
|
-
fontWeight: font.weight.semibold,
|
|
64
|
-
},
|
|
65
|
-
separator: {
|
|
66
|
-
height: 1,
|
|
67
|
-
marginHorizontal: spacing.m,
|
|
68
|
-
marginVertical: spacing.xxs,
|
|
69
|
-
},
|
|
70
|
-
item: {
|
|
71
|
-
flexDirection: 'row',
|
|
72
|
-
alignItems: 'center',
|
|
73
|
-
paddingHorizontal: spacing.m,
|
|
74
|
-
paddingVertical: spacing.s,
|
|
75
|
-
minHeight: 48,
|
|
76
|
-
gap: spacing.s,
|
|
77
|
-
},
|
|
78
|
-
itemText: {
|
|
79
|
-
fontFamily: font.family.body,
|
|
80
|
-
fontSize: font.size.body,
|
|
81
|
-
lineHeight: lineHeight.body,
|
|
82
|
-
},
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
export function DropdownMenu({
|
|
86
|
-
trigger,
|
|
87
|
-
items,
|
|
88
|
-
title = 'Menu',
|
|
89
|
-
style,
|
|
90
|
-
}: Readonly<DropdownMenuProps>) {
|
|
91
|
-
const { colors } = useTheme();
|
|
92
|
-
const [open, setOpen] = useState(false);
|
|
93
|
-
const screenHeight = Dimensions.get('window').height;
|
|
94
|
-
|
|
95
|
-
const slideAnim = useRef(new Animated.Value(screenHeight)).current;
|
|
96
|
-
const backdropAnim = useRef(new Animated.Value(0)).current;
|
|
97
|
-
|
|
98
|
-
useEffect(() => {
|
|
99
|
-
if (open) {
|
|
100
|
-
Animated.parallel([
|
|
101
|
-
Animated.timing(slideAnim, {
|
|
102
|
-
toValue: 0,
|
|
103
|
-
duration: 250,
|
|
104
|
-
useNativeDriver: true,
|
|
105
|
-
}),
|
|
106
|
-
Animated.timing(backdropAnim, {
|
|
107
|
-
toValue: 1,
|
|
108
|
-
duration: 250,
|
|
109
|
-
useNativeDriver: true,
|
|
110
|
-
}),
|
|
111
|
-
]).start();
|
|
112
|
-
} else {
|
|
113
|
-
Animated.parallel([
|
|
114
|
-
Animated.timing(slideAnim, {
|
|
115
|
-
toValue: screenHeight,
|
|
116
|
-
duration: 200,
|
|
117
|
-
useNativeDriver: true,
|
|
118
|
-
}),
|
|
119
|
-
Animated.timing(backdropAnim, {
|
|
120
|
-
toValue: 0,
|
|
121
|
-
duration: 200,
|
|
122
|
-
useNativeDriver: true,
|
|
123
|
-
}),
|
|
124
|
-
]).start();
|
|
125
|
-
}
|
|
126
|
-
}, [open, slideAnim, backdropAnim, screenHeight]);
|
|
127
|
-
|
|
128
|
-
const handleItemPress = (item: DropdownMenuItem) => {
|
|
129
|
-
item.onPress?.();
|
|
130
|
-
setOpen(false);
|
|
131
|
-
};
|
|
132
|
-
|
|
133
|
-
return (
|
|
134
|
-
<View style={style}>
|
|
135
|
-
{React.cloneElement(trigger as ReactElement<Record<string, unknown>>, {
|
|
136
|
-
onPress: () => setOpen(true),
|
|
137
|
-
accessibilityRole: 'button',
|
|
138
|
-
accessibilityLabel: title,
|
|
139
|
-
})}
|
|
140
|
-
|
|
141
|
-
<Modal
|
|
142
|
-
visible={open}
|
|
143
|
-
transparent
|
|
144
|
-
animationType="none"
|
|
145
|
-
onRequestClose={() => setOpen(false)}
|
|
146
|
-
>
|
|
147
|
-
<View style={styles.overlay}>
|
|
148
|
-
<Animated.View
|
|
149
|
-
style={[
|
|
150
|
-
StyleSheet.absoluteFill,
|
|
151
|
-
{ backgroundColor: 'rgba(0, 0, 0, 0.5)', opacity: backdropAnim },
|
|
152
|
-
]}
|
|
153
|
-
>
|
|
154
|
-
<Pressable
|
|
155
|
-
style={StyleSheet.absoluteFill}
|
|
156
|
-
onPress={() => setOpen(false)}
|
|
157
|
-
accessibilityRole="button"
|
|
158
|
-
accessibilityLabel="Close menu"
|
|
159
|
-
/>
|
|
160
|
-
</Animated.View>
|
|
161
|
-
<Animated.View
|
|
162
|
-
style={[
|
|
163
|
-
styles.sheet,
|
|
164
|
-
{
|
|
165
|
-
backgroundColor: colors.colorBg,
|
|
166
|
-
transform: [{ translateY: slideAnim }],
|
|
167
|
-
},
|
|
168
|
-
]}
|
|
169
|
-
>
|
|
170
|
-
<Pressable
|
|
171
|
-
onPress={() => {
|
|
172
|
-
/* prevent close when pressing sheet */
|
|
173
|
-
}}
|
|
174
|
-
>
|
|
175
|
-
<SafeAreaView>
|
|
176
|
-
<View
|
|
177
|
-
style={[
|
|
178
|
-
styles.sheetHeader,
|
|
179
|
-
{ borderBottomColor: colors.colorBgSubtle },
|
|
180
|
-
]}
|
|
181
|
-
>
|
|
182
|
-
<Text style={[styles.sheetTitle, { color: colors.colorOnBg }]}>
|
|
183
|
-
{title}
|
|
184
|
-
</Text>
|
|
185
|
-
<Pressable
|
|
186
|
-
accessibilityRole="button"
|
|
187
|
-
accessibilityLabel="Close"
|
|
188
|
-
onPress={() => setOpen(false)}
|
|
189
|
-
hitSlop={8}
|
|
190
|
-
>
|
|
191
|
-
<Text
|
|
192
|
-
style={[
|
|
193
|
-
styles.closeText,
|
|
194
|
-
{ color: colors.colorInteractive },
|
|
195
|
-
]}
|
|
196
|
-
>
|
|
197
|
-
Done
|
|
198
|
-
</Text>
|
|
199
|
-
</Pressable>
|
|
200
|
-
</View>
|
|
201
|
-
<FlatList
|
|
202
|
-
data={items}
|
|
203
|
-
keyExtractor={(item) => item.id}
|
|
204
|
-
renderItem={({ item }) => (
|
|
205
|
-
<>
|
|
206
|
-
{item.separator && (
|
|
207
|
-
<View
|
|
208
|
-
style={[
|
|
209
|
-
styles.separator,
|
|
210
|
-
{ backgroundColor: colors.colorBgSubtle },
|
|
211
|
-
]}
|
|
212
|
-
accessibilityRole="none"
|
|
213
|
-
/>
|
|
214
|
-
)}
|
|
215
|
-
<Pressable
|
|
216
|
-
accessibilityRole="menuitem"
|
|
217
|
-
accessibilityLabel={item.label}
|
|
218
|
-
accessibilityState={{ disabled: item.disabled }}
|
|
219
|
-
disabled={item.disabled}
|
|
220
|
-
onPress={() => handleItemPress(item)}
|
|
221
|
-
style={({ pressed }) => [
|
|
222
|
-
styles.item,
|
|
223
|
-
pressed && { backgroundColor: colors.colorBgSubtle },
|
|
224
|
-
item.disabled && { opacity: 0.4 },
|
|
225
|
-
]}
|
|
226
|
-
>
|
|
227
|
-
{!!item.icon && (
|
|
228
|
-
<View
|
|
229
|
-
importantForAccessibility="no-hide-descendants"
|
|
230
|
-
accessibilityElementsHidden={true}
|
|
231
|
-
>
|
|
232
|
-
{item.icon}
|
|
233
|
-
</View>
|
|
234
|
-
)}
|
|
235
|
-
<Text
|
|
236
|
-
style={[
|
|
237
|
-
styles.itemText,
|
|
238
|
-
{ color: colors.colorOnBg },
|
|
239
|
-
]}
|
|
240
|
-
>
|
|
241
|
-
{item.label}
|
|
242
|
-
</Text>
|
|
243
|
-
</Pressable>
|
|
244
|
-
</>
|
|
245
|
-
)}
|
|
246
|
-
/>
|
|
247
|
-
</SafeAreaView>
|
|
248
|
-
</Pressable>
|
|
249
|
-
</Animated.View>
|
|
250
|
-
</View>
|
|
251
|
-
</Modal>
|
|
252
|
-
</View>
|
|
253
|
-
);
|
|
254
|
-
}
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
import { Meta, Canvas, ArgTypes } from '@storybook/blocks';
|
|
2
|
-
import * as Stories from './Popover.native.stories';
|
|
3
|
-
|
|
4
|
-
<Meta of={Stories} />
|
|
5
|
-
|
|
6
|
-
# Popover (React Native)
|
|
7
|
-
|
|
8
|
-
A popover overlay that displays content in a centered modal. The trigger element opens the popover on press; tapping the backdrop dismisses it.
|
|
9
|
-
|
|
10
|
-
> **Status: alpha** — API may change before stable release.
|
|
11
|
-
|
|
12
|
-
## Usage
|
|
13
|
-
|
|
14
|
-
```tsx
|
|
15
|
-
import { Popover } from '@boostdev/design-system-components';
|
|
16
|
-
|
|
17
|
-
<Popover
|
|
18
|
-
content={<Text>Additional information here.</Text>}
|
|
19
|
-
accessibilityLabel="More info"
|
|
20
|
-
>
|
|
21
|
-
<Button>Show Info</Button>
|
|
22
|
-
</Popover>
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
Wrap your tree in `ThemeProvider` (once, at the app root):
|
|
26
|
-
|
|
27
|
-
```tsx
|
|
28
|
-
import { ThemeProvider } from '@boostdev/design-system-components/native/ThemeContext';
|
|
29
|
-
|
|
30
|
-
export default function App() {
|
|
31
|
-
return <ThemeProvider><YourApp /></ThemeProvider>;
|
|
32
|
-
}
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
## Examples
|
|
36
|
-
|
|
37
|
-
### Default
|
|
38
|
-
<Canvas of={Stories.Default} />
|
|
39
|
-
|
|
40
|
-
### Rich content
|
|
41
|
-
<Canvas of={Stories.RichContent} />
|
|
42
|
-
|
|
43
|
-
## Props
|
|
44
|
-
|
|
45
|
-
<ArgTypes of={Stories} />
|
|
46
|
-
|
|
47
|
-
## Props reference
|
|
48
|
-
|
|
49
|
-
| Prop | Type | Default | Description |
|
|
50
|
-
|------|------|---------|-------------|
|
|
51
|
-
| `children` | `ReactNode` | — | Trigger element that opens the popover on press |
|
|
52
|
-
| `content` | `ReactNode` | — | Content displayed inside the popover panel |
|
|
53
|
-
| `accessibilityLabel` | `string` | `'Open popover'` | Label for the trigger and panel |
|
|
54
|
-
| `style` | `StyleProp<ViewStyle>` | — | Override wrapper styles |
|
|
55
|
-
|
|
56
|
-
## Accessibility
|
|
57
|
-
|
|
58
|
-
- Trigger has `accessibilityRole="button"` with `expanded` state
|
|
59
|
-
- Backdrop press closes the popover
|
|
60
|
-
- Android back button triggers `onRequestClose` to dismiss
|
|
61
|
-
- Panel has shadow elevation for visual depth
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
import { render, screen, fireEvent } from '@testing-library/react';
|
|
2
|
-
import { Text, Pressable } from 'react-native';
|
|
3
|
-
import { ThemeProvider } from '../../../native/ThemeContext';
|
|
4
|
-
import { Popover } from './Popover.native';
|
|
5
|
-
|
|
6
|
-
function renderWithTheme(ui: React.ReactElement) {
|
|
7
|
-
return render(<ThemeProvider>{ui}</ThemeProvider>);
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
function Trigger({ children, ...rest }: { children: string; onPress?: () => void }) {
|
|
11
|
-
return <Pressable {...rest}><Text>{children}</Text></Pressable>;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
describe('Popover (native)', () => {
|
|
15
|
-
it('renders the trigger element', () => {
|
|
16
|
-
renderWithTheme(
|
|
17
|
-
<Popover content={<Text>Popover content</Text>}>
|
|
18
|
-
<Trigger>Trigger</Trigger>
|
|
19
|
-
</Popover>,
|
|
20
|
-
);
|
|
21
|
-
expect(screen.getByText('Trigger')).toBeInTheDocument();
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
it('does not show content initially', () => {
|
|
25
|
-
renderWithTheme(
|
|
26
|
-
<Popover content={<Text>Hidden content</Text>}>
|
|
27
|
-
<Trigger>Trigger</Trigger>
|
|
28
|
-
</Popover>,
|
|
29
|
-
);
|
|
30
|
-
expect(screen.queryByText('Hidden content')).not.toBeInTheDocument();
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
it('shows content when trigger is pressed', () => {
|
|
34
|
-
renderWithTheme(
|
|
35
|
-
<Popover content={<Text>Visible content</Text>} accessibilityLabel="Info">
|
|
36
|
-
<Trigger>Trigger</Trigger>
|
|
37
|
-
</Popover>,
|
|
38
|
-
);
|
|
39
|
-
fireEvent.click(screen.getByRole('button', { name: 'Info' }));
|
|
40
|
-
expect(screen.getByText('Visible content')).toBeInTheDocument();
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
it('renders trigger with button role and custom accessibility label', () => {
|
|
44
|
-
renderWithTheme(
|
|
45
|
-
<Popover content={<Text>Content</Text>} accessibilityLabel="Details">
|
|
46
|
-
<Trigger>Trigger</Trigger>
|
|
47
|
-
</Popover>,
|
|
48
|
-
);
|
|
49
|
-
const trigger = screen.getByRole('button', { name: 'Details' });
|
|
50
|
-
expect(trigger).toBeInTheDocument();
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
it('renders backdrop with close label when open', () => {
|
|
54
|
-
renderWithTheme(
|
|
55
|
-
<Popover content={<Text>Closable</Text>} accessibilityLabel="Test">
|
|
56
|
-
<Trigger>Trigger</Trigger>
|
|
57
|
-
</Popover>,
|
|
58
|
-
);
|
|
59
|
-
fireEvent.click(screen.getByRole('button', { name: 'Test' }));
|
|
60
|
-
expect(screen.getByText('Closable')).toBeInTheDocument();
|
|
61
|
-
// Verify the close backdrop button exists
|
|
62
|
-
expect(screen.getByRole('button', { name: 'Close popover' })).toBeInTheDocument();
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
it('uses default accessibility label when none provided', () => {
|
|
66
|
-
renderWithTheme(
|
|
67
|
-
<Popover content={<Text>Content</Text>}>
|
|
68
|
-
<Trigger>Trigger</Trigger>
|
|
69
|
-
</Popover>,
|
|
70
|
-
);
|
|
71
|
-
expect(screen.getByRole('button', { name: 'Open popover' })).toBeInTheDocument();
|
|
72
|
-
});
|
|
73
|
-
});
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { Text, View } from 'react-native';
|
|
3
|
-
import type { Meta, StoryObj } from '@storybook/react';
|
|
4
|
-
import { ThemeProvider } from '../../../native/ThemeContext';
|
|
5
|
-
import { Popover } from './Popover.native';
|
|
6
|
-
import { Button } from '../Button/Button.native';
|
|
7
|
-
|
|
8
|
-
const meta = {
|
|
9
|
-
tags: ['!stable', 'alpha'],
|
|
10
|
-
title: 'React Native/Interaction/Popover',
|
|
11
|
-
component: Popover,
|
|
12
|
-
decorators: [(Story) => <ThemeProvider colorScheme="light"><Story /></ThemeProvider>],
|
|
13
|
-
parameters: { layout: 'centered' },
|
|
14
|
-
} satisfies Meta<typeof Popover>;
|
|
15
|
-
|
|
16
|
-
export default meta;
|
|
17
|
-
type Story = StoryObj<typeof meta>;
|
|
18
|
-
|
|
19
|
-
export const Default: Story = {
|
|
20
|
-
render: () => (
|
|
21
|
-
<Popover
|
|
22
|
-
content={<Text>This is popover content displayed in a modal overlay.</Text>}
|
|
23
|
-
accessibilityLabel="More info"
|
|
24
|
-
>
|
|
25
|
-
<Button>Show Popover</Button>
|
|
26
|
-
</Popover>
|
|
27
|
-
),
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
export const RichContent: Story = {
|
|
31
|
-
render: () => (
|
|
32
|
-
<Popover
|
|
33
|
-
content={
|
|
34
|
-
<View style={{ gap: 8 }}>
|
|
35
|
-
<Text style={{ fontWeight: '600', fontSize: 16 }}>Help</Text>
|
|
36
|
-
<Text>Press the button below to submit your response. You can edit your answer before submitting.</Text>
|
|
37
|
-
</View>
|
|
38
|
-
}
|
|
39
|
-
accessibilityLabel="Help information"
|
|
40
|
-
>
|
|
41
|
-
<Button variant="outline">Help</Button>
|
|
42
|
-
</Popover>
|
|
43
|
-
),
|
|
44
|
-
};
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
import React, { ReactElement, ReactNode, useState } from 'react';
|
|
2
|
-
import {
|
|
3
|
-
Modal,
|
|
4
|
-
View,
|
|
5
|
-
Pressable,
|
|
6
|
-
StyleSheet,
|
|
7
|
-
StyleProp,
|
|
8
|
-
ViewStyle,
|
|
9
|
-
} from 'react-native';
|
|
10
|
-
import { spacing, border } from '../../../native/tokens';
|
|
11
|
-
import { useTheme } from '../../../native/ThemeContext';
|
|
12
|
-
|
|
13
|
-
interface PopoverProps {
|
|
14
|
-
children: ReactElement;
|
|
15
|
-
content: ReactNode;
|
|
16
|
-
accessibilityLabel?: string;
|
|
17
|
-
style?: StyleProp<ViewStyle>;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const styles = StyleSheet.create({
|
|
21
|
-
wrapper: {
|
|
22
|
-
alignSelf: 'flex-start',
|
|
23
|
-
},
|
|
24
|
-
overlay: {
|
|
25
|
-
flex: 1,
|
|
26
|
-
justifyContent: 'center',
|
|
27
|
-
alignItems: 'center',
|
|
28
|
-
backgroundColor: 'rgba(0, 0, 0, 0.25)',
|
|
29
|
-
padding: spacing.m,
|
|
30
|
-
},
|
|
31
|
-
panel: {
|
|
32
|
-
width: '100%',
|
|
33
|
-
maxWidth: 360,
|
|
34
|
-
borderRadius: border.radius.s,
|
|
35
|
-
padding: spacing.m,
|
|
36
|
-
shadowColor: '#000',
|
|
37
|
-
shadowOffset: { width: 0, height: 2 },
|
|
38
|
-
shadowOpacity: 0.15,
|
|
39
|
-
shadowRadius: 8,
|
|
40
|
-
elevation: 4,
|
|
41
|
-
},
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
export function Popover({
|
|
45
|
-
children,
|
|
46
|
-
content,
|
|
47
|
-
accessibilityLabel,
|
|
48
|
-
style,
|
|
49
|
-
}: Readonly<PopoverProps>) {
|
|
50
|
-
const { colors } = useTheme();
|
|
51
|
-
const [isOpen, setIsOpen] = useState(false);
|
|
52
|
-
|
|
53
|
-
return (
|
|
54
|
-
<View style={[styles.wrapper, style]}>
|
|
55
|
-
{React.cloneElement(children as ReactElement<Record<string, unknown>>, {
|
|
56
|
-
onPress: () => setIsOpen(true),
|
|
57
|
-
accessibilityRole: 'button',
|
|
58
|
-
accessibilityLabel: accessibilityLabel ?? 'Open popover',
|
|
59
|
-
})}
|
|
60
|
-
|
|
61
|
-
<Modal
|
|
62
|
-
visible={isOpen}
|
|
63
|
-
transparent
|
|
64
|
-
animationType="fade"
|
|
65
|
-
onRequestClose={() => setIsOpen(false)}
|
|
66
|
-
>
|
|
67
|
-
<Pressable
|
|
68
|
-
style={styles.overlay}
|
|
69
|
-
onPress={() => setIsOpen(false)}
|
|
70
|
-
accessibilityRole="button"
|
|
71
|
-
accessibilityLabel="Close popover"
|
|
72
|
-
>
|
|
73
|
-
<Pressable
|
|
74
|
-
style={[styles.panel, { backgroundColor: colors.colorBg }]}
|
|
75
|
-
onPress={() => {
|
|
76
|
-
/* prevent close when pressing panel */
|
|
77
|
-
}}
|
|
78
|
-
accessibilityRole="none"
|
|
79
|
-
accessibilityLabel={accessibilityLabel}
|
|
80
|
-
>
|
|
81
|
-
{content}
|
|
82
|
-
</Pressable>
|
|
83
|
-
</Pressable>
|
|
84
|
-
</Modal>
|
|
85
|
-
</View>
|
|
86
|
-
);
|
|
87
|
-
}
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import { Meta, Canvas, ArgTypes } from '@storybook/blocks';
|
|
2
|
-
import * as Stories from './Rating.native.stories';
|
|
3
|
-
|
|
4
|
-
<Meta of={Stories} />
|
|
5
|
-
|
|
6
|
-
# Rating (React Native)
|
|
7
|
-
|
|
8
|
-
React Native read-only star rating display using text characters. Shows filled and empty stars based on the `value` prop.
|
|
9
|
-
|
|
10
|
-
> **Status: alpha** — API may change before stable release.
|
|
11
|
-
|
|
12
|
-
## Usage
|
|
13
|
-
|
|
14
|
-
```tsx
|
|
15
|
-
import { Rating } from '@boostdev/design-system-components';
|
|
16
|
-
|
|
17
|
-
<Rating value={4} />
|
|
18
|
-
<Rating value={7} max={10} />
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
## Examples
|
|
22
|
-
|
|
23
|
-
### Default (3 of 5)
|
|
24
|
-
<Canvas of={Stories.Default} />
|
|
25
|
-
|
|
26
|
-
### Full rating
|
|
27
|
-
<Canvas of={Stories.Full} />
|
|
28
|
-
|
|
29
|
-
### Empty rating
|
|
30
|
-
<Canvas of={Stories.Empty} />
|
|
31
|
-
|
|
32
|
-
### Custom max
|
|
33
|
-
<Canvas of={Stories.CustomMax} />
|
|
34
|
-
|
|
35
|
-
### All variants
|
|
36
|
-
<Canvas of={Stories.AllVariants} />
|
|
37
|
-
|
|
38
|
-
## Props
|
|
39
|
-
|
|
40
|
-
<ArgTypes of={Stories} />
|
|
41
|
-
|
|
42
|
-
## Props reference
|
|
43
|
-
|
|
44
|
-
| Prop | Type | Default | Description |
|
|
45
|
-
|------|------|---------|-------------|
|
|
46
|
-
| `value` | `number` | — | Number of filled stars |
|
|
47
|
-
| `max` | `number` | `5` | Total number of stars |
|
|
48
|
-
| `accessibilityLabel` | `string` | `"{value} out of {max} stars"` | Screen reader label |
|
|
49
|
-
| `style` | `StyleProp<ViewStyle>` | — | Override container styles |
|
|
50
|
-
|
|
51
|
-
## Accessibility
|
|
52
|
-
|
|
53
|
-
- Uses `accessibilityRole="image"` since the rating is a visual representation
|
|
54
|
-
- Auto-generates an accessibility label like "3 out of 5 stars" when not provided
|
|
55
|
-
- Individual stars are hidden from assistive technologies
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { render, screen } from '@testing-library/react';
|
|
2
|
-
import { ThemeProvider } from '../../../native/ThemeContext';
|
|
3
|
-
import { Rating } from './Rating.native';
|
|
4
|
-
|
|
5
|
-
function renderWithTheme(ui: React.ReactElement) {
|
|
6
|
-
return render(<ThemeProvider>{ui}</ThemeProvider>);
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
describe('Rating (native)', () => {
|
|
10
|
-
it('has image role with auto-generated accessible label', () => {
|
|
11
|
-
renderWithTheme(<Rating value={3} />);
|
|
12
|
-
expect(screen.getByRole('img', { name: '3 out of 5 stars' })).toBeInTheDocument();
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
it('renders the correct number of filled stars', () => {
|
|
16
|
-
renderWithTheme(<Rating value={3} />);
|
|
17
|
-
const stars = screen.getAllByText('\u2605');
|
|
18
|
-
expect(stars).toHaveLength(5);
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
it('renders all stars as filled characters', () => {
|
|
22
|
-
renderWithTheme(<Rating value={2} />);
|
|
23
|
-
const stars = screen.getAllByText('\u2605');
|
|
24
|
-
expect(stars).toHaveLength(5);
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
it('uses custom max value', () => {
|
|
28
|
-
renderWithTheme(<Rating value={7} max={10} />);
|
|
29
|
-
expect(screen.getByRole('img', { name: '7 out of 10 stars' })).toBeInTheDocument();
|
|
30
|
-
const stars = screen.getAllByText('\u2605');
|
|
31
|
-
expect(stars).toHaveLength(10);
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
it('uses custom accessibilityLabel when provided', () => {
|
|
35
|
-
renderWithTheme(<Rating value={4} accessibilityLabel="Excellent rating" />);
|
|
36
|
-
expect(screen.getByRole('img', { name: 'Excellent rating' })).toBeInTheDocument();
|
|
37
|
-
});
|
|
38
|
-
});
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import type { Meta, StoryObj } from '@storybook/react';
|
|
3
|
-
import { ThemeProvider } from '../../../native/ThemeContext';
|
|
4
|
-
import { Rating } from './Rating.native';
|
|
5
|
-
|
|
6
|
-
const meta = {
|
|
7
|
-
tags: ['!stable', 'alpha'],
|
|
8
|
-
title: 'React Native/Interaction/Rating',
|
|
9
|
-
component: Rating,
|
|
10
|
-
decorators: [(Story) => <ThemeProvider colorScheme="light"><Story /></ThemeProvider>],
|
|
11
|
-
parameters: { layout: 'centered' },
|
|
12
|
-
argTypes: {
|
|
13
|
-
value: { control: { type: 'range', min: 0, max: 5, step: 1 } },
|
|
14
|
-
max: { control: { type: 'number', min: 1, max: 10 } },
|
|
15
|
-
},
|
|
16
|
-
} satisfies Meta<typeof Rating>;
|
|
17
|
-
|
|
18
|
-
export default meta;
|
|
19
|
-
type Story = StoryObj<typeof meta>;
|
|
20
|
-
|
|
21
|
-
export const Default: Story = { args: { value: 3 } };
|
|
22
|
-
export const Full: Story = { args: { value: 5 } };
|
|
23
|
-
export const Empty: Story = { args: { value: 0 } };
|
|
24
|
-
export const CustomMax: Story = { args: { value: 7, max: 10 } };
|
|
25
|
-
export const WithLabel: Story = {
|
|
26
|
-
args: { value: 4, accessibilityLabel: 'Customer rating: 4 out of 5' },
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
export const AllVariants: Story = {
|
|
30
|
-
render: () => (
|
|
31
|
-
<div style={{ display: 'flex', flexDirection: 'column', gap: '12px' }}>
|
|
32
|
-
{[0, 1, 2, 3, 4, 5].map(v => (
|
|
33
|
-
<Rating key={v} value={v} />
|
|
34
|
-
))}
|
|
35
|
-
</div>
|
|
36
|
-
),
|
|
37
|
-
};
|