@draftbit/core 47.0.0-alpha.0 → 47.0.0-df8093.2
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/lib/commonjs/components/Banner.js +168 -0
- package/lib/commonjs/components/Banner.js.map +1 -0
- package/lib/commonjs/components/Stepper.js +1 -0
- package/lib/commonjs/index.js +14 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/mappings/View.js.map +1 -1
- package/lib/commonjs/mappings/WebView.js.map +1 -1
- package/lib/module/components/Banner.js +158 -0
- package/lib/module/components/Banner.js.map +1 -0
- package/lib/module/components/Stepper.js +1 -0
- package/lib/module/index.js +2 -0
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/src/components/Banner.d.ts +23 -0
- package/lib/typescript/src/components/Banner.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +2 -0
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/Provider.js +9 -0
- package/src/components/Accordion/AccordionGroup.js +44 -0
- package/src/components/Accordion/AccordionItem.js +32 -0
- package/src/components/Accordion/index.js +2 -0
- package/src/components/ActionSheet/ActionSheet.js +45 -0
- package/src/components/ActionSheet/ActionSheetCancel.js +6 -0
- package/src/components/ActionSheet/ActionSheetItem.js +30 -0
- package/src/components/ActionSheet/index.js +3 -0
- package/src/components/Banner.js +109 -0
- package/src/components/Banner.tsx +204 -0
- package/src/components/Button.js +114 -0
- package/src/components/Checkbox/Checkbox.js +63 -0
- package/src/components/Checkbox/CheckboxGroup.js +21 -0
- package/src/components/Checkbox/CheckboxGroupRow.js +77 -0
- package/src/components/Checkbox/CheckboxRow.js +78 -0
- package/src/components/Checkbox/context.js +14 -0
- package/src/components/Checkbox/index.js +3 -0
- package/src/components/Config.js +64 -0
- package/src/components/DatePicker/DatePicker.js +368 -0
- package/src/components/DatePicker/DatePickerComponent.js +13 -0
- package/src/components/DatePicker/DatePickerComponent.web.js +30 -0
- package/src/components/DatePicker/DatePickerComponentType.js +1 -0
- package/src/components/DeprecatedButton.js +95 -0
- package/src/components/Elevation.js +20 -0
- package/src/components/FormRow.js +19 -0
- package/src/components/IconButton.js +35 -0
- package/src/components/Layout.js +50 -0
- package/src/components/NumberInput.js +49 -0
- package/src/components/Picker/Picker.js +267 -0
- package/src/components/Picker/PickerComponent.android.js +69 -0
- package/src/components/Picker/PickerComponent.ios.js +79 -0
- package/src/components/Picker/PickerComponent.web.js +70 -0
- package/src/components/Picker/PickerTypes.js +1 -0
- package/src/components/Portal/Portal.js +35 -0
- package/src/components/Portal/PortalConsumer.js +27 -0
- package/src/components/Portal/PortalHost.js +107 -0
- package/src/components/Portal/PortalManager.js +32 -0
- package/src/components/RadioButton/RadioButton.js +17 -0
- package/src/components/RadioButton/RadioButtonFieldGroup.js +17 -0
- package/src/components/RadioButton/RadioButtonGroup.js +43 -0
- package/src/components/RadioButton/RadioButtonRow.js +76 -0
- package/src/components/RadioButton/context.js +14 -0
- package/src/components/RadioButton/index.js +4 -0
- package/src/components/SVG.js +13 -0
- package/src/components/ScreenContainer.js +34 -0
- package/src/components/Slider.js +63 -0
- package/src/components/StarRating.js +50 -0
- package/src/components/Stepper.js +39 -0
- package/src/components/Surface.js +32 -0
- package/src/components/Swiper/Swiper.js +29 -0
- package/src/components/Swiper/SwiperItem.js +9 -0
- package/src/components/Swiper/index.js +2 -0
- package/src/components/Switch.js +56 -0
- package/src/components/Text.js +33 -0
- package/src/components/TextField.js +428 -0
- package/src/components/Touchable.js +12 -0
- package/src/components/Touchable.web.js +2 -0
- package/src/constants.js +10 -0
- package/src/hooks.js +12 -0
- package/src/index.js +35 -0
- package/src/index.tsx +2 -0
- package/src/interfaces/Icon.js +8 -0
- package/src/mappings/Accordion.js +41 -0
- package/src/mappings/AccordionItem.js +16 -0
- package/src/mappings/ActionSheet.js +13 -0
- package/src/mappings/ActionSheetCancel.js +19 -0
- package/src/mappings/ActionSheetItem.js +23 -0
- package/src/mappings/ActivityIndicator.js +58 -0
- package/src/mappings/AudioPlayer.js +20 -0
- package/src/mappings/BlurView.js +42 -0
- package/src/mappings/Button.js +87 -0
- package/src/mappings/Checkbox.js +46 -0
- package/src/mappings/CheckboxGroup.js +26 -0
- package/src/mappings/CheckboxRow.js +61 -0
- package/src/mappings/CustomCode.js +8 -0
- package/src/mappings/DatePicker.js +157 -0
- package/src/mappings/Fetch.js +13 -0
- package/src/mappings/FlashList.js +33 -0
- package/src/mappings/FlatList.js +24 -0
- package/src/mappings/Icon.js +32 -0
- package/src/mappings/IconButton.js +35 -0
- package/src/mappings/Image.js +35 -0
- package/src/mappings/ImageBackground.js +29 -0
- package/src/mappings/KeyboardAvoidingView.js +41 -0
- package/src/mappings/KeyboardAwareScrollView.js +50 -0
- package/src/mappings/Layout.js +200 -0
- package/src/mappings/LinearGradient.js +77 -0
- package/src/mappings/MapCallout.js +21 -0
- package/src/mappings/MapMarker.js +47 -0
- package/src/mappings/MapView.js +139 -0
- package/src/mappings/Modal.js +42 -0
- package/src/mappings/NumberInput.js +254 -0
- package/src/mappings/Picker.js +148 -0
- package/src/mappings/RadioButton.js +51 -0
- package/src/mappings/RadioButtonGroup.js +17 -0
- package/src/mappings/RadioButtonRow.js +42 -0
- package/src/mappings/SVG.js +20 -0
- package/src/mappings/SafeAreaView.js +33 -0
- package/src/mappings/ScrollView.js +31 -0
- package/src/mappings/Slider.js +60 -0
- package/src/mappings/StarRating.js +43 -0
- package/src/mappings/Stepper.js +29 -0
- package/src/mappings/Surface.js +14 -0
- package/src/mappings/Swiper.js +60 -0
- package/src/mappings/SwiperItem.js +8 -0
- package/src/mappings/Switch.js +81 -0
- package/src/mappings/Text.js +251 -0
- package/src/mappings/TextArea.js +263 -0
- package/src/mappings/TextField.js +381 -0
- package/src/mappings/TextInput.js +391 -0
- package/src/mappings/Touchable.js +17 -0
- package/src/mappings/Video.js +81 -0
- package/src/mappings/View.js +207 -0
- package/src/mappings/WebView.js +88 -0
- package/src/styles/DarkTheme.js +26 -0
- package/src/styles/DefaultTheme.js +111 -0
- package/src/styles/fonts.js +62 -0
- package/src/styles/overlay.js +60 -0
- package/src/styles/shadow.js +51 -0
- package/src/theming.js +3 -0
- package/src/utilities.js +102 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { Pressable, StyleSheet, View, } from "react-native";
|
|
3
|
+
import Text from "../Text";
|
|
4
|
+
import { extractStyles } from "../../utilities";
|
|
5
|
+
import { withTheme } from "../../theming";
|
|
6
|
+
const AccordionItem = ({ Icon, icon, label, style, iconColor, theme, ...rest }) => {
|
|
7
|
+
const { textStyles, viewStyles } = extractStyles(style);
|
|
8
|
+
return (React.createElement(Pressable, { style: [styles.container, viewStyles], ...rest },
|
|
9
|
+
React.createElement(View, { style: styles.row },
|
|
10
|
+
icon ? (React.createElement(Icon, { name: icon, size: 24, color: iconColor || theme.colors.primary })) : null,
|
|
11
|
+
React.createElement(View, { style: [styles.item, styles.content] },
|
|
12
|
+
React.createElement(Text, { selectable: false, style: textStyles }, label)))));
|
|
13
|
+
};
|
|
14
|
+
const styles = StyleSheet.create({
|
|
15
|
+
container: {
|
|
16
|
+
padding: 8,
|
|
17
|
+
},
|
|
18
|
+
row: {
|
|
19
|
+
flexDirection: "row",
|
|
20
|
+
alignItems: "center",
|
|
21
|
+
paddingLeft: 8,
|
|
22
|
+
},
|
|
23
|
+
item: {
|
|
24
|
+
marginVertical: 6,
|
|
25
|
+
paddingLeft: 8,
|
|
26
|
+
},
|
|
27
|
+
content: {
|
|
28
|
+
flex: 1,
|
|
29
|
+
justifyContent: "center",
|
|
30
|
+
},
|
|
31
|
+
});
|
|
32
|
+
export default withTheme(AccordionItem);
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { View, StyleSheet } from "react-native";
|
|
3
|
+
import Portal from "../Portal/Portal";
|
|
4
|
+
import Touchable from "../Touchable";
|
|
5
|
+
import ActionSheetCancel from "./ActionSheetCancel";
|
|
6
|
+
const ActionSheet = ({ visible = false, onClose, children }) => {
|
|
7
|
+
return visible ? (React.createElement(Portal, null,
|
|
8
|
+
React.createElement(Touchable, { style: styles.wrapper, onPress: onClose },
|
|
9
|
+
React.createElement(View, { style: styles.overlay }),
|
|
10
|
+
React.createElement(View, { style: styles.groupWrapper },
|
|
11
|
+
React.createElement(View, { style: styles.group }, React.Children.toArray(children).filter((child) => (child === null || child === void 0 ? void 0 : child.type) !== ActionSheetCancel)),
|
|
12
|
+
React.createElement(View, { style: styles.group }, React.Children.toArray(children).filter((child) => child.type === ActionSheetCancel)))))) : (React.createElement(React.Fragment, null));
|
|
13
|
+
};
|
|
14
|
+
const styles = StyleSheet.create({
|
|
15
|
+
wrapper: {
|
|
16
|
+
flex: 1,
|
|
17
|
+
display: "flex",
|
|
18
|
+
flexDirection: "column",
|
|
19
|
+
},
|
|
20
|
+
overlay: {
|
|
21
|
+
position: "absolute",
|
|
22
|
+
top: 0,
|
|
23
|
+
left: 0,
|
|
24
|
+
right: 0,
|
|
25
|
+
bottom: 0,
|
|
26
|
+
backgroundColor: "#000000",
|
|
27
|
+
opacity: 0.3,
|
|
28
|
+
},
|
|
29
|
+
groupWrapper: {
|
|
30
|
+
flex: 1,
|
|
31
|
+
flexDirection: "column",
|
|
32
|
+
justifyContent: "flex-end",
|
|
33
|
+
display: "flex",
|
|
34
|
+
marginBottom: 25,
|
|
35
|
+
},
|
|
36
|
+
group: {
|
|
37
|
+
display: "flex",
|
|
38
|
+
flexDirection: "column",
|
|
39
|
+
borderRadius: 10,
|
|
40
|
+
marginHorizontal: 7,
|
|
41
|
+
marginVertical: 2.5,
|
|
42
|
+
overflow: "hidden",
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
export default ActionSheet;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import ActionSheetItem from "./ActionSheetItem";
|
|
3
|
+
const ActionSheetCancel = ({ label = "Cancel", color, style, onPress, }) => {
|
|
4
|
+
return (React.createElement(ActionSheetItem, { label: label, color: color || "#FF453A", style: [style], onPress: onPress }));
|
|
5
|
+
};
|
|
6
|
+
export default ActionSheetCancel;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Text, StyleSheet, TouchableOpacity, } from "react-native";
|
|
3
|
+
import { extractStyles } from "../../utilities";
|
|
4
|
+
const ActionSheetItem = ({ label, style, color, onPress, }) => {
|
|
5
|
+
const { textStyles, viewStyles } = extractStyles(style);
|
|
6
|
+
return (React.createElement(TouchableOpacity, { activeOpacity: 0.7, style: [styles.wrapper, viewStyles], onPress: onPress },
|
|
7
|
+
React.createElement(Text, { style: [styles.label, textStyles, { color }] }, label)));
|
|
8
|
+
};
|
|
9
|
+
const styles = StyleSheet.create({
|
|
10
|
+
wrapper: {
|
|
11
|
+
borderBottomWidth: StyleSheet.hairlineWidth,
|
|
12
|
+
borderBottomColor: "#CCCCCC",
|
|
13
|
+
backgroundColor: "#F1F1F1",
|
|
14
|
+
minHeight: 50,
|
|
15
|
+
overflow: "hidden",
|
|
16
|
+
display: "flex",
|
|
17
|
+
justifyContent: "center",
|
|
18
|
+
},
|
|
19
|
+
label: {
|
|
20
|
+
fontSize: 16,
|
|
21
|
+
textAlign: "center",
|
|
22
|
+
color: "#0A84FF",
|
|
23
|
+
fontWeight: "500",
|
|
24
|
+
overflow: "hidden",
|
|
25
|
+
paddingHorizontal: 20,
|
|
26
|
+
paddingVertical: 10,
|
|
27
|
+
alignSelf: "center",
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
export default ActionSheetItem;
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { Button, Text, View, StyleSheet, Animated, } from "react-native";
|
|
3
|
+
import Surface from "./Surface";
|
|
4
|
+
import shadow from "../styles/shadow";
|
|
5
|
+
import { withTheme } from "../theming";
|
|
6
|
+
const ELEVATION = 1;
|
|
7
|
+
const DEFAULT_MAX_WIDTH = 960;
|
|
8
|
+
const Banner = ({ initiallyVisible = true, dismissable = true, icon, buttonColor, content, contentStyle, style, theme, Icon, ...rest }) => {
|
|
9
|
+
const [visible, setVisible] = React.useState(initiallyVisible);
|
|
10
|
+
React.useEffect(() => {
|
|
11
|
+
if (initiallyVisible) {
|
|
12
|
+
setVisible(true);
|
|
13
|
+
}
|
|
14
|
+
}, [initiallyVisible]);
|
|
15
|
+
const { current: position } = React.useRef(new Animated.Value(visible ? 1 : 0));
|
|
16
|
+
const [layout, setLayout] = React.useState({
|
|
17
|
+
height: 0,
|
|
18
|
+
measured: false,
|
|
19
|
+
});
|
|
20
|
+
React.useEffect(() => {
|
|
21
|
+
if (visible) {
|
|
22
|
+
// show
|
|
23
|
+
Animated.timing(position, {
|
|
24
|
+
duration: 250,
|
|
25
|
+
toValue: 1,
|
|
26
|
+
useNativeDriver: false,
|
|
27
|
+
}).start();
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
// hide
|
|
31
|
+
Animated.timing(position, {
|
|
32
|
+
duration: 200,
|
|
33
|
+
toValue: 0,
|
|
34
|
+
useNativeDriver: false,
|
|
35
|
+
}).start();
|
|
36
|
+
}
|
|
37
|
+
}, [visible, position]);
|
|
38
|
+
const handleLayout = ({ nativeEvent }) => {
|
|
39
|
+
const { height } = nativeEvent.layout;
|
|
40
|
+
setLayout({ height, measured: true });
|
|
41
|
+
};
|
|
42
|
+
// The banner animation has 2 parts:
|
|
43
|
+
// 1. Blank spacer element which animates its height to move the content
|
|
44
|
+
// 2. Actual banner which animates its translateY
|
|
45
|
+
// In initial render, we position everything normally and measure the height of the banner
|
|
46
|
+
// Once we have the height, we apply the height to the spacer and switch the banner to position: absolute
|
|
47
|
+
// We need this because we need to move the content below as if banner's height was being animated
|
|
48
|
+
// However we can't animated banner's height directly as it'll also resize the content inside
|
|
49
|
+
const height = Animated.multiply(position, layout.height);
|
|
50
|
+
const translateY = Animated.multiply(Animated.add(position, -1), layout.height);
|
|
51
|
+
return (React.createElement(Surface, { ...rest, style: [styles.container, shadow(ELEVATION), style] },
|
|
52
|
+
React.createElement(View, { style: [styles.wrapper, contentStyle] },
|
|
53
|
+
React.createElement(Animated.View, { style: { height } }),
|
|
54
|
+
React.createElement(Animated.View, { onLayout: handleLayout, style: [
|
|
55
|
+
layout.measured || !visible
|
|
56
|
+
? // If we have measured banner's height or it's invisible,
|
|
57
|
+
// Position it absolutely, the layout will be taken care of the spacer
|
|
58
|
+
[styles.absolute, { transform: [{ translateY }] }]
|
|
59
|
+
: // Otherwise position it normally
|
|
60
|
+
null,
|
|
61
|
+
!layout.measured && !visible
|
|
62
|
+
? // If we haven't measured banner's height yet and it's invisible,
|
|
63
|
+
// hide it with opacity: 0 so user doesn't see it
|
|
64
|
+
{ opacity: 0 }
|
|
65
|
+
: null,
|
|
66
|
+
] },
|
|
67
|
+
React.createElement(View, { style: [styles.content, { marginBottom: dismissable ? 0 : 16 }] },
|
|
68
|
+
icon ? (React.createElement(View, { style: styles.icon },
|
|
69
|
+
React.createElement(Icon, { name: icon, size: 40 }))) : null,
|
|
70
|
+
React.createElement(Text, { style: [styles.message, { color: theme.colors.text }], accessibilityLiveRegion: visible ? "polite" : "none", accessibilityRole: "alert" }, content)),
|
|
71
|
+
dismissable ? (React.createElement(View, { style: styles.actions },
|
|
72
|
+
React.createElement(Button, { color: buttonColor || theme.colors.primary, title: "Close", onPress: () => setVisible(false) }))) : null))));
|
|
73
|
+
};
|
|
74
|
+
const styles = StyleSheet.create({
|
|
75
|
+
container: {
|
|
76
|
+
elevation: ELEVATION,
|
|
77
|
+
},
|
|
78
|
+
wrapper: {
|
|
79
|
+
overflow: "hidden",
|
|
80
|
+
alignSelf: "center",
|
|
81
|
+
width: "100%",
|
|
82
|
+
maxWidth: DEFAULT_MAX_WIDTH,
|
|
83
|
+
},
|
|
84
|
+
absolute: {
|
|
85
|
+
position: "absolute",
|
|
86
|
+
top: 0,
|
|
87
|
+
width: "100%",
|
|
88
|
+
},
|
|
89
|
+
content: {
|
|
90
|
+
flexDirection: "row",
|
|
91
|
+
justifyContent: "flex-start",
|
|
92
|
+
marginHorizontal: 8,
|
|
93
|
+
marginTop: 16,
|
|
94
|
+
marginBottom: 0,
|
|
95
|
+
},
|
|
96
|
+
icon: {
|
|
97
|
+
margin: 8,
|
|
98
|
+
},
|
|
99
|
+
message: {
|
|
100
|
+
flex: 1,
|
|
101
|
+
margin: 8,
|
|
102
|
+
},
|
|
103
|
+
actions: {
|
|
104
|
+
flexDirection: "row",
|
|
105
|
+
justifyContent: "flex-end",
|
|
106
|
+
margin: 8,
|
|
107
|
+
},
|
|
108
|
+
});
|
|
109
|
+
export default withTheme(Banner);
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import {
|
|
3
|
+
Button,
|
|
4
|
+
Text,
|
|
5
|
+
View,
|
|
6
|
+
ViewStyle,
|
|
7
|
+
StyleSheet,
|
|
8
|
+
StyleProp,
|
|
9
|
+
Animated,
|
|
10
|
+
} from "react-native";
|
|
11
|
+
import Surface from "./Surface";
|
|
12
|
+
import type { IconSlot } from "../interfaces/Icon";
|
|
13
|
+
import shadow from "../styles/shadow";
|
|
14
|
+
import { withTheme } from "../theming";
|
|
15
|
+
import type { Theme } from "../styles/DefaultTheme";
|
|
16
|
+
|
|
17
|
+
const ELEVATION = 1;
|
|
18
|
+
const DEFAULT_MAX_WIDTH = 960;
|
|
19
|
+
|
|
20
|
+
type Props = {
|
|
21
|
+
initiallyVisible: boolean;
|
|
22
|
+
dismissable: boolean;
|
|
23
|
+
buttonColor?: string;
|
|
24
|
+
icon?: string;
|
|
25
|
+
content?: string;
|
|
26
|
+
contentStyle?: StyleProp<ViewStyle>;
|
|
27
|
+
style?: StyleProp<ViewStyle>;
|
|
28
|
+
ref?: React.RefObject<View>;
|
|
29
|
+
/**
|
|
30
|
+
* @optional
|
|
31
|
+
*/
|
|
32
|
+
theme: Theme;
|
|
33
|
+
} & IconSlot;
|
|
34
|
+
|
|
35
|
+
type NativeEvent = {
|
|
36
|
+
nativeEvent: {
|
|
37
|
+
layout: {
|
|
38
|
+
x: number;
|
|
39
|
+
y: number;
|
|
40
|
+
width: number;
|
|
41
|
+
height: number;
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const Banner: React.FC<React.PropsWithChildren<Props>> = ({
|
|
47
|
+
initiallyVisible = true,
|
|
48
|
+
dismissable = true,
|
|
49
|
+
icon,
|
|
50
|
+
buttonColor,
|
|
51
|
+
content,
|
|
52
|
+
contentStyle,
|
|
53
|
+
style,
|
|
54
|
+
theme,
|
|
55
|
+
Icon,
|
|
56
|
+
...rest
|
|
57
|
+
}) => {
|
|
58
|
+
const [visible, setVisible] = React.useState(initiallyVisible);
|
|
59
|
+
|
|
60
|
+
React.useEffect(() => {
|
|
61
|
+
if (initiallyVisible) {
|
|
62
|
+
setVisible(true);
|
|
63
|
+
}
|
|
64
|
+
}, [initiallyVisible]);
|
|
65
|
+
|
|
66
|
+
const { current: position } = React.useRef<Animated.Value>(
|
|
67
|
+
new Animated.Value(visible ? 1 : 0)
|
|
68
|
+
);
|
|
69
|
+
const [layout, setLayout] = React.useState<{
|
|
70
|
+
height: number;
|
|
71
|
+
measured: boolean;
|
|
72
|
+
}>({
|
|
73
|
+
height: 0,
|
|
74
|
+
measured: false,
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
React.useEffect(() => {
|
|
78
|
+
if (visible) {
|
|
79
|
+
// show
|
|
80
|
+
Animated.timing(position, {
|
|
81
|
+
duration: 250,
|
|
82
|
+
toValue: 1,
|
|
83
|
+
useNativeDriver: false,
|
|
84
|
+
}).start();
|
|
85
|
+
} else {
|
|
86
|
+
// hide
|
|
87
|
+
Animated.timing(position, {
|
|
88
|
+
duration: 200,
|
|
89
|
+
toValue: 0,
|
|
90
|
+
useNativeDriver: false,
|
|
91
|
+
}).start();
|
|
92
|
+
}
|
|
93
|
+
}, [visible, position]);
|
|
94
|
+
|
|
95
|
+
const handleLayout = ({ nativeEvent }: NativeEvent) => {
|
|
96
|
+
const { height } = nativeEvent.layout;
|
|
97
|
+
setLayout({ height, measured: true });
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
// The banner animation has 2 parts:
|
|
101
|
+
// 1. Blank spacer element which animates its height to move the content
|
|
102
|
+
// 2. Actual banner which animates its translateY
|
|
103
|
+
// In initial render, we position everything normally and measure the height of the banner
|
|
104
|
+
// Once we have the height, we apply the height to the spacer and switch the banner to position: absolute
|
|
105
|
+
// We need this because we need to move the content below as if banner's height was being animated
|
|
106
|
+
// However we can't animated banner's height directly as it'll also resize the content inside
|
|
107
|
+
const height = Animated.multiply(position, layout.height);
|
|
108
|
+
|
|
109
|
+
const translateY = Animated.multiply(
|
|
110
|
+
Animated.add(position, -1),
|
|
111
|
+
layout.height
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
return (
|
|
115
|
+
<Surface
|
|
116
|
+
{...rest}
|
|
117
|
+
style={[styles.container, shadow(ELEVATION) as ViewStyle, style]}
|
|
118
|
+
>
|
|
119
|
+
<View style={[styles.wrapper, contentStyle]}>
|
|
120
|
+
<Animated.View style={{ height }} />
|
|
121
|
+
<Animated.View
|
|
122
|
+
onLayout={handleLayout}
|
|
123
|
+
style={[
|
|
124
|
+
layout.measured || !visible
|
|
125
|
+
? // If we have measured banner's height or it's invisible,
|
|
126
|
+
// Position it absolutely, the layout will be taken care of the spacer
|
|
127
|
+
[styles.absolute, { transform: [{ translateY }] }]
|
|
128
|
+
: // Otherwise position it normally
|
|
129
|
+
null,
|
|
130
|
+
!layout.measured && !visible
|
|
131
|
+
? // If we haven't measured banner's height yet and it's invisible,
|
|
132
|
+
// hide it with opacity: 0 so user doesn't see it
|
|
133
|
+
{ opacity: 0 }
|
|
134
|
+
: null,
|
|
135
|
+
]}
|
|
136
|
+
>
|
|
137
|
+
<View
|
|
138
|
+
style={[styles.content, { marginBottom: dismissable ? 0 : 16 }]}
|
|
139
|
+
>
|
|
140
|
+
{icon ? (
|
|
141
|
+
<View style={styles.icon}>
|
|
142
|
+
<Icon name={icon} size={40} />
|
|
143
|
+
</View>
|
|
144
|
+
) : null}
|
|
145
|
+
<Text
|
|
146
|
+
style={[styles.message, { color: theme.colors.text }]}
|
|
147
|
+
accessibilityLiveRegion={visible ? "polite" : "none"}
|
|
148
|
+
accessibilityRole="alert"
|
|
149
|
+
>
|
|
150
|
+
{content}
|
|
151
|
+
</Text>
|
|
152
|
+
</View>
|
|
153
|
+
{dismissable ? (
|
|
154
|
+
<View style={styles.actions}>
|
|
155
|
+
<Button
|
|
156
|
+
color={buttonColor || theme.colors.primary}
|
|
157
|
+
title="Close"
|
|
158
|
+
onPress={() => setVisible(false)}
|
|
159
|
+
/>
|
|
160
|
+
</View>
|
|
161
|
+
) : null}
|
|
162
|
+
</Animated.View>
|
|
163
|
+
</View>
|
|
164
|
+
</Surface>
|
|
165
|
+
);
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
const styles = StyleSheet.create({
|
|
169
|
+
container: {
|
|
170
|
+
elevation: ELEVATION,
|
|
171
|
+
},
|
|
172
|
+
wrapper: {
|
|
173
|
+
overflow: "hidden",
|
|
174
|
+
alignSelf: "center",
|
|
175
|
+
width: "100%",
|
|
176
|
+
maxWidth: DEFAULT_MAX_WIDTH,
|
|
177
|
+
},
|
|
178
|
+
absolute: {
|
|
179
|
+
position: "absolute",
|
|
180
|
+
top: 0,
|
|
181
|
+
width: "100%",
|
|
182
|
+
},
|
|
183
|
+
content: {
|
|
184
|
+
flexDirection: "row",
|
|
185
|
+
justifyContent: "flex-start",
|
|
186
|
+
marginHorizontal: 8,
|
|
187
|
+
marginTop: 16,
|
|
188
|
+
marginBottom: 0,
|
|
189
|
+
},
|
|
190
|
+
icon: {
|
|
191
|
+
margin: 8,
|
|
192
|
+
},
|
|
193
|
+
message: {
|
|
194
|
+
flex: 1,
|
|
195
|
+
margin: 8,
|
|
196
|
+
},
|
|
197
|
+
actions: {
|
|
198
|
+
flexDirection: "row",
|
|
199
|
+
justifyContent: "flex-end",
|
|
200
|
+
margin: 8,
|
|
201
|
+
},
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
export default withTheme(Banner);
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { Text, Pressable, Platform, StyleSheet, ActivityIndicator, } from "react-native";
|
|
3
|
+
import { withTheme } from "../theming";
|
|
4
|
+
const CONSTANTS = {
|
|
5
|
+
baseHeight: 42,
|
|
6
|
+
borderRadius: 4,
|
|
7
|
+
padding: 8,
|
|
8
|
+
icon: 24,
|
|
9
|
+
};
|
|
10
|
+
function Base({ Icon, icon, title, onPress, loading, disabled, style, ...props }) {
|
|
11
|
+
const { color, fontFamily, fontWeight, fontSize, lineHeight, letterSpacing, textTransform, textAlign, textDecorationLine, textDecorationColor, textDecorationStyle, ...buttonStyles } = StyleSheet.flatten(style || {});
|
|
12
|
+
const titleStyles = {
|
|
13
|
+
color,
|
|
14
|
+
fontFamily,
|
|
15
|
+
fontWeight,
|
|
16
|
+
fontSize,
|
|
17
|
+
lineHeight,
|
|
18
|
+
letterSpacing,
|
|
19
|
+
textTransform,
|
|
20
|
+
textAlign,
|
|
21
|
+
textDecorationLine,
|
|
22
|
+
textDecorationColor,
|
|
23
|
+
textDecorationStyle,
|
|
24
|
+
};
|
|
25
|
+
if (textAlign === "left") {
|
|
26
|
+
buttonStyles.justifyContent = "flex-start";
|
|
27
|
+
}
|
|
28
|
+
if (textAlign === "right") {
|
|
29
|
+
buttonStyles.justifyContent = "flex-end";
|
|
30
|
+
}
|
|
31
|
+
return (React.createElement(Pressable, { onPress: onPress, disabled: disabled || loading, style: ({ pressed }) => {
|
|
32
|
+
return [
|
|
33
|
+
styles.base,
|
|
34
|
+
{
|
|
35
|
+
opacity: pressed || disabled ? 0.75 : 1,
|
|
36
|
+
},
|
|
37
|
+
buttonStyles,
|
|
38
|
+
];
|
|
39
|
+
}, ...props },
|
|
40
|
+
loading ? (React.createElement(ActivityIndicator, { size: "small", color: color, style: styles.loading })) : null,
|
|
41
|
+
icon && !loading ? (React.createElement(Icon, { name: icon, color: color, style: styles.icon, size: CONSTANTS.icon })) : null,
|
|
42
|
+
React.createElement(Text, { style: titleStyles }, title)));
|
|
43
|
+
}
|
|
44
|
+
const Solid = ({ style, theme, ...props }) => {
|
|
45
|
+
return (React.createElement(Base, { style: [
|
|
46
|
+
{
|
|
47
|
+
color: "#FFF",
|
|
48
|
+
borderRadius: theme.roundness,
|
|
49
|
+
backgroundColor: theme.colors.primary,
|
|
50
|
+
},
|
|
51
|
+
style,
|
|
52
|
+
], ...props }));
|
|
53
|
+
};
|
|
54
|
+
const ButtonSolid = withTheme(Solid);
|
|
55
|
+
export { ButtonSolid };
|
|
56
|
+
const Button = withTheme(Solid);
|
|
57
|
+
export { Button };
|
|
58
|
+
const Outline = ({ style, theme, ...props }) => {
|
|
59
|
+
return (React.createElement(Base, { style: [
|
|
60
|
+
styles.outline,
|
|
61
|
+
{
|
|
62
|
+
borderRadius: theme.roundness,
|
|
63
|
+
borderColor: theme.colors.primary,
|
|
64
|
+
color: theme.colors.primary,
|
|
65
|
+
},
|
|
66
|
+
style,
|
|
67
|
+
], ...props }));
|
|
68
|
+
};
|
|
69
|
+
const ButtonOutline = withTheme(Outline);
|
|
70
|
+
export { ButtonOutline };
|
|
71
|
+
const styles = StyleSheet.create({
|
|
72
|
+
base: {
|
|
73
|
+
position: "relative",
|
|
74
|
+
flexDirection: "row",
|
|
75
|
+
alignItems: "center",
|
|
76
|
+
justifyContent: "center",
|
|
77
|
+
minHeight: CONSTANTS.baseHeight,
|
|
78
|
+
paddingHorizontal: 12,
|
|
79
|
+
fontFamily: "System",
|
|
80
|
+
fontWeight: "700",
|
|
81
|
+
...Platform.select({
|
|
82
|
+
web: {
|
|
83
|
+
cursor: "pointer",
|
|
84
|
+
userSelect: "none",
|
|
85
|
+
},
|
|
86
|
+
}),
|
|
87
|
+
},
|
|
88
|
+
outline: {
|
|
89
|
+
backgroundColor: "transparent",
|
|
90
|
+
borderWidth: 1,
|
|
91
|
+
},
|
|
92
|
+
bare: {
|
|
93
|
+
backgroundColor: "transparent",
|
|
94
|
+
padding: 0,
|
|
95
|
+
minHeight: undefined,
|
|
96
|
+
},
|
|
97
|
+
loading: {
|
|
98
|
+
marginRight: 6,
|
|
99
|
+
},
|
|
100
|
+
icon: {
|
|
101
|
+
...Platform.select({
|
|
102
|
+
web: {
|
|
103
|
+
marginTop: 1,
|
|
104
|
+
marginRight: 4,
|
|
105
|
+
alignSelf: "center",
|
|
106
|
+
},
|
|
107
|
+
default: {
|
|
108
|
+
marginBottom: 2,
|
|
109
|
+
marginRight: 4,
|
|
110
|
+
alignSelf: "center",
|
|
111
|
+
},
|
|
112
|
+
}),
|
|
113
|
+
},
|
|
114
|
+
});
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { View, StyleSheet, } from "react-native";
|
|
3
|
+
import { useTheme } from "../../theming";
|
|
4
|
+
import Touchable from "../Touchable";
|
|
5
|
+
import { usePrevious } from "../../hooks";
|
|
6
|
+
const Checkbox = ({ Icon, status, disabled = false, onPress, onCheck, onUncheck, color, uncheckedColor, defaultValue, checkedIcon = "MaterialCommunityIcons/checkbox-marked", uncheckedIcon = "MaterialCommunityIcons/checkbox-blank-outline", size = 24, style, ...rest }) => {
|
|
7
|
+
const [internalValue, setInternalValue] = React.useState(status || defaultValue || false);
|
|
8
|
+
React.useEffect(() => {
|
|
9
|
+
if (status != null) {
|
|
10
|
+
setInternalValue(status);
|
|
11
|
+
}
|
|
12
|
+
}, [status]);
|
|
13
|
+
// This special logic is to handle weird APIs like Airtable that return
|
|
14
|
+
// true or undefined for a boolean
|
|
15
|
+
const previousDefaultValue = usePrevious(defaultValue);
|
|
16
|
+
React.useEffect(() => {
|
|
17
|
+
if (defaultValue !== previousDefaultValue) {
|
|
18
|
+
setInternalValue(Boolean(defaultValue));
|
|
19
|
+
}
|
|
20
|
+
}, [defaultValue, previousDefaultValue]);
|
|
21
|
+
const { colors } = useTheme();
|
|
22
|
+
const checkboxColor = internalValue
|
|
23
|
+
? color || colors.primary
|
|
24
|
+
: uncheckedColor || colors.primary;
|
|
25
|
+
const handlePress = () => {
|
|
26
|
+
const newValue = !internalValue;
|
|
27
|
+
setInternalValue(newValue);
|
|
28
|
+
onPress === null || onPress === void 0 ? void 0 : onPress(newValue);
|
|
29
|
+
if (newValue) {
|
|
30
|
+
onCheck === null || onCheck === void 0 ? void 0 : onCheck();
|
|
31
|
+
}
|
|
32
|
+
if (!newValue) {
|
|
33
|
+
onUncheck === null || onUncheck === void 0 ? void 0 : onUncheck();
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
return (React.createElement(Touchable, { ...rest, onPress: handlePress, disabled: disabled, accessibilityState: { disabled }, accessibilityRole: "button", accessibilityLiveRegion: "polite", style: [styles.container, style, { width: size, height: size }] },
|
|
37
|
+
React.createElement(Icon, { style: styles.icon, name: internalValue ? checkedIcon : uncheckedIcon, size: size, color: checkboxColor }),
|
|
38
|
+
React.createElement(View, { style: [StyleSheet.absoluteFill, styles.fillContainer] },
|
|
39
|
+
React.createElement(View, { style: [
|
|
40
|
+
styles.fill,
|
|
41
|
+
{ opacity: disabled ? 0.5 : 1 },
|
|
42
|
+
{ borderColor: checkboxColor },
|
|
43
|
+
] }))));
|
|
44
|
+
};
|
|
45
|
+
const styles = StyleSheet.create({
|
|
46
|
+
container: {
|
|
47
|
+
borderRadius: 18,
|
|
48
|
+
},
|
|
49
|
+
fillContainer: {
|
|
50
|
+
alignItems: "center",
|
|
51
|
+
justifyContent: "center",
|
|
52
|
+
},
|
|
53
|
+
icon: {
|
|
54
|
+
alignSelf: "center",
|
|
55
|
+
},
|
|
56
|
+
fill: {
|
|
57
|
+
borderRadius: 5,
|
|
58
|
+
width: 30,
|
|
59
|
+
height: 30,
|
|
60
|
+
alignSelf: "center",
|
|
61
|
+
},
|
|
62
|
+
});
|
|
63
|
+
export default Checkbox;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { View } from "react-native";
|
|
3
|
+
import { checkboxGroupContext, Direction } from "./context";
|
|
4
|
+
const { Provider } = checkboxGroupContext;
|
|
5
|
+
const CheckboxGroup = ({ direction = Direction.Vertical, values, onValueChange = () => { }, style, children, ...rest }) => {
|
|
6
|
+
const _containerStyle = [
|
|
7
|
+
{
|
|
8
|
+
flexDirection: direction === Direction.Horizontal ? "row" : "column",
|
|
9
|
+
overflow: "hidden",
|
|
10
|
+
},
|
|
11
|
+
];
|
|
12
|
+
if (direction !== Direction.Vertical) {
|
|
13
|
+
_containerStyle.push({
|
|
14
|
+
alignItems: "center",
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
return (React.createElement(View, { style: [{ minHeight: 40 }, style], ...rest },
|
|
18
|
+
React.createElement(Provider, { value: { values, onValueChange, direction } },
|
|
19
|
+
React.createElement(View, { style: _containerStyle }, children))));
|
|
20
|
+
};
|
|
21
|
+
export default CheckboxGroup;
|