@wq/material-native 2.0.0-alpha.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/babel.config.cjs +1 -1
- package/jest.config.js +1 -5
- package/package.json +16 -17
- package/src/App.js +23 -5
- package/src/components/{ExpansionPanel.js → Accordion.js} +2 -2
- package/src/components/BottomNavigation.js +3 -0
- package/src/components/BottomNavigationAction.js +3 -0
- package/src/components/CheckboxButton.js +25 -2
- package/src/components/Fab.js +0 -1
- package/src/components/IconButton.js +1 -1
- package/src/components/Img.js +102 -0
- package/src/components/ListItem.js +17 -1
- package/src/components/NavMenuFixed.js +3 -0
- package/src/components/NavMenuPopup.js +3 -0
- package/src/components/Popup.js +18 -2
- package/src/components/RadioButton.js +25 -2
- package/src/components/SidePanel.js +93 -2
- package/src/components/Switch.js +17 -2
- package/src/components/TabGroup.js +38 -0
- package/src/components/TabItem.js +16 -0
- package/src/components/TableCell.js +23 -1
- package/src/components/index.js +17 -10
- package/src/icons.js +16 -1
- package/src/inputs/Checkbox.js +22 -13
- package/src/inputs/DateTime.js +8 -5
- package/src/inputs/File.js +175 -2
- package/src/inputs/FileArray.js +12 -0
- package/src/inputs/HelperText.js +28 -2
- package/src/inputs/Hidden.js +5 -4
- package/src/inputs/Image.js +5 -2
- package/src/inputs/Input.js +17 -11
- package/src/inputs/Radio.js +31 -2
- package/src/inputs/Select.js +22 -16
- package/src/inputs/Toggle.js +37 -2
- package/src/inputs/index.js +8 -0
- package/setup-jest.js +0 -5
- package/src/components/FileArray.js +0 -3
- /package/src/{components → inputs}/Fieldset.js +0 -0
- /package/src/{components → inputs}/FieldsetArray.js +0 -0
- /package/src/{components → inputs}/FlatFieldset.js +0 -0
package/babel.config.cjs
CHANGED
package/jest.config.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wq/material-native",
|
|
3
|
-
"version": "2.0.0
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "React Native and Expo bindings for @wq/material",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.js",
|
|
@@ -28,31 +28,30 @@
|
|
|
28
28
|
},
|
|
29
29
|
"homepage": "https://wq.io/@wq/material",
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@wq/react": "^2.0.0
|
|
32
|
-
"date-fns": "^2.
|
|
31
|
+
"@wq/react": "^2.0.0",
|
|
32
|
+
"date-fns": "^2.30.0"
|
|
33
33
|
},
|
|
34
34
|
"peerDependencies": {
|
|
35
35
|
"@react-native-async-storage/async-storage": "*",
|
|
36
|
-
"@react-native-community/datetimepicker": "*",
|
|
37
|
-
"@react-native-community/masked-view": "*",
|
|
38
36
|
"@react-native-community/netinfo": "*",
|
|
39
|
-
"@react-navigation/native": "*",
|
|
40
37
|
"@react-navigation/stack": "*",
|
|
38
|
+
"expo-application": "*",
|
|
39
|
+
"expo-document-picker": "*",
|
|
40
|
+
"expo-image-picker": "*",
|
|
41
41
|
"react-native-modal-datetime-picker": "*",
|
|
42
42
|
"react-native-paper": "*",
|
|
43
43
|
"react-native-picker-select": "*"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
|
-
"@react-native-async-storage/async-storage": "^1.
|
|
47
|
-
"@react-native-community/
|
|
48
|
-
"@react-
|
|
49
|
-
"
|
|
50
|
-
"
|
|
51
|
-
"
|
|
52
|
-
"
|
|
53
|
-
"
|
|
54
|
-
"react-native-
|
|
55
|
-
"react-native-
|
|
56
|
-
"react-native-picker-select": "^8.0.4"
|
|
46
|
+
"@react-native-async-storage/async-storage": "^1.19.1",
|
|
47
|
+
"@react-native-community/netinfo": "^9.4.1",
|
|
48
|
+
"@react-navigation/stack": "^6.3.17",
|
|
49
|
+
"expo-application": "^5.3.0",
|
|
50
|
+
"expo-document-picker": "^11.5.4",
|
|
51
|
+
"expo-image-picker": "^14.3.2",
|
|
52
|
+
"jest-expo": "^49.0.0",
|
|
53
|
+
"react-native-modal-datetime-picker": "^17.0.0",
|
|
54
|
+
"react-native-paper": "^5.10.1",
|
|
55
|
+
"react-native-picker-select": "github:Expensify/react-native-picker-select#eae0585"
|
|
57
56
|
}
|
|
58
57
|
}
|
package/src/App.js
CHANGED
|
@@ -1,11 +1,20 @@
|
|
|
1
1
|
import React, { useMemo } from "react";
|
|
2
2
|
import { App as DefaultApp, usePlugin } from "@wq/react";
|
|
3
3
|
import {
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
MD2LightTheme,
|
|
5
|
+
MD3LightTheme,
|
|
6
|
+
MD2DarkTheme,
|
|
7
|
+
MD3DarkTheme,
|
|
6
8
|
Provider as PaperProvider,
|
|
7
9
|
} from "react-native-paper";
|
|
8
10
|
|
|
11
|
+
const THEMES = {
|
|
12
|
+
"light-2": MD2LightTheme,
|
|
13
|
+
"light-3": MD3LightTheme,
|
|
14
|
+
"dark-2": MD2DarkTheme,
|
|
15
|
+
"dark-3": MD3DarkTheme,
|
|
16
|
+
};
|
|
17
|
+
|
|
9
18
|
export default function App() {
|
|
10
19
|
const { theme: configTheme } = usePlugin("material").config,
|
|
11
20
|
theme = useMemo(() => createTheme(configTheme), [configTheme]),
|
|
@@ -26,9 +35,18 @@ export default function App() {
|
|
|
26
35
|
);
|
|
27
36
|
}
|
|
28
37
|
|
|
29
|
-
function createTheme({
|
|
38
|
+
function createTheme({
|
|
39
|
+
type = "light",
|
|
40
|
+
version = 3,
|
|
41
|
+
primary,
|
|
42
|
+
secondary,
|
|
43
|
+
background,
|
|
44
|
+
}) {
|
|
30
45
|
const colors = {},
|
|
31
|
-
base = type
|
|
46
|
+
base = THEMES[`${type}-${version}`];
|
|
47
|
+
if (!base) {
|
|
48
|
+
console.warn(`Unknown base theme type=${type} version=${version}`);
|
|
49
|
+
}
|
|
32
50
|
if (primary) {
|
|
33
51
|
colors.primary = primary;
|
|
34
52
|
}
|
|
@@ -41,7 +59,7 @@ function createTheme({ type, primary, secondary, background }) {
|
|
|
41
59
|
return {
|
|
42
60
|
...base,
|
|
43
61
|
colors: {
|
|
44
|
-
...base.colors,
|
|
62
|
+
...(base || {}).colors,
|
|
45
63
|
...colors,
|
|
46
64
|
},
|
|
47
65
|
};
|
|
@@ -2,7 +2,7 @@ import React from "react";
|
|
|
2
2
|
import { List } from "react-native-paper";
|
|
3
3
|
import PropTypes from "prop-types";
|
|
4
4
|
|
|
5
|
-
export default function
|
|
5
|
+
export default function Accordion({ summary, children, open, onToggle }) {
|
|
6
6
|
let handleToggle;
|
|
7
7
|
if (onToggle) {
|
|
8
8
|
handleToggle = () => onToggle(!open);
|
|
@@ -14,7 +14,7 @@ export default function ExpansionPanel({ summary, children, open, onToggle }) {
|
|
|
14
14
|
);
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
Accordion.propTypes = {
|
|
18
18
|
summary: PropTypes.node,
|
|
19
19
|
children: PropTypes.node,
|
|
20
20
|
open: PropTypes.bool,
|
|
@@ -1,3 +1,26 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Checkbox as PaperCheckbox, useTheme } from "react-native-paper";
|
|
3
|
+
import PropTypes from "prop-types";
|
|
4
|
+
|
|
5
|
+
const STATUSES = {
|
|
6
|
+
true: "checked",
|
|
7
|
+
false: "unchecked",
|
|
8
|
+
undefined: "indeterminate",
|
|
9
|
+
null: "indeterminate",
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export default function Checkbox({ checked, color, ...props }) {
|
|
13
|
+
const status = STATUSES[checked],
|
|
14
|
+
theme = useTheme();
|
|
15
|
+
if (color === "primary") {
|
|
16
|
+
color = theme.colors.primary;
|
|
17
|
+
} else if (color === "secondary") {
|
|
18
|
+
color = theme.colors.accent;
|
|
19
|
+
}
|
|
20
|
+
return <PaperCheckbox status={status} {...props} />;
|
|
3
21
|
}
|
|
22
|
+
|
|
23
|
+
Checkbox.propTypes = {
|
|
24
|
+
checked: PropTypes.bool,
|
|
25
|
+
color: PropTypes.string,
|
|
26
|
+
};
|
package/src/components/Fab.js
CHANGED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import React, { useState, useEffect } from "react";
|
|
2
|
+
import { Image, TouchableOpacity, Dimensions } from "react-native";
|
|
3
|
+
import PropTypes from "prop-types";
|
|
4
|
+
|
|
5
|
+
export default function Img({ src, onPress, onClick, style, ...props }) {
|
|
6
|
+
const [source, setSource] = useState(src ? { uri: src } : null);
|
|
7
|
+
useEffect(() => {
|
|
8
|
+
if (!src) {
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
if (typeof src !== "string") {
|
|
12
|
+
setSource(src);
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
Image.getSize(src, (width, height) => {
|
|
16
|
+
setSource({ uri: src, width, height });
|
|
17
|
+
});
|
|
18
|
+
}, [src]);
|
|
19
|
+
|
|
20
|
+
let resizeMode;
|
|
21
|
+
if (
|
|
22
|
+
style &&
|
|
23
|
+
typeof style.maxHeight === "number" &&
|
|
24
|
+
typeof style.maxWidth === "string" &&
|
|
25
|
+
style.maxWidth.endsWith("vw")
|
|
26
|
+
) {
|
|
27
|
+
resizeMode = "contain";
|
|
28
|
+
const ratio =
|
|
29
|
+
source && source.width && source.height
|
|
30
|
+
? source.width / source.height
|
|
31
|
+
: 1,
|
|
32
|
+
maxWidth =
|
|
33
|
+
(+style.maxWidth.replace(/vw/g, "") / 100) *
|
|
34
|
+
Dimensions.get("window").width;
|
|
35
|
+
style = {
|
|
36
|
+
...style,
|
|
37
|
+
maxHeight: undefined,
|
|
38
|
+
maxWidth: undefined,
|
|
39
|
+
height: style.maxHeight,
|
|
40
|
+
width: Math.min(ratio * style.maxHeight, maxWidth),
|
|
41
|
+
};
|
|
42
|
+
} else if (
|
|
43
|
+
style &&
|
|
44
|
+
typeof style.maxHeight === "string" &&
|
|
45
|
+
typeof style.maxWidth === "string"
|
|
46
|
+
) {
|
|
47
|
+
resizeMode = "contain";
|
|
48
|
+
style = {
|
|
49
|
+
...style,
|
|
50
|
+
maxHeight: undefined,
|
|
51
|
+
maxWidth: undefined,
|
|
52
|
+
height: style.maxHeight.replace("vh", "%"),
|
|
53
|
+
width: style.maxWidth.replace("vw", "%"),
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const hasSize =
|
|
58
|
+
(source && (source === src || (source.width && source.height))) ||
|
|
59
|
+
props.width ||
|
|
60
|
+
props.height ||
|
|
61
|
+
(style && style.width) ||
|
|
62
|
+
(style && style.height);
|
|
63
|
+
if (src && !hasSize) {
|
|
64
|
+
return null;
|
|
65
|
+
} else if (onPress || onClick) {
|
|
66
|
+
return (
|
|
67
|
+
<TouchableOpacity
|
|
68
|
+
onPress={onPress || onClick}
|
|
69
|
+
style={{
|
|
70
|
+
...style,
|
|
71
|
+
alignItems: "center",
|
|
72
|
+
justifyContent: "center",
|
|
73
|
+
}}
|
|
74
|
+
>
|
|
75
|
+
<Image
|
|
76
|
+
resizeMode={resizeMode}
|
|
77
|
+
style={style}
|
|
78
|
+
source={source}
|
|
79
|
+
{...props}
|
|
80
|
+
/>
|
|
81
|
+
</TouchableOpacity>
|
|
82
|
+
);
|
|
83
|
+
} else {
|
|
84
|
+
return (
|
|
85
|
+
<Image
|
|
86
|
+
resizeMode={resizeMode}
|
|
87
|
+
style={style}
|
|
88
|
+
source={source}
|
|
89
|
+
{...props}
|
|
90
|
+
/>
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
Img.propTypes = {
|
|
96
|
+
src: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
|
97
|
+
width: PropTypes.number,
|
|
98
|
+
height: PropTypes.number,
|
|
99
|
+
onPress: PropTypes.func,
|
|
100
|
+
onClick: PropTypes.func,
|
|
101
|
+
style: PropTypes.object,
|
|
102
|
+
};
|
|
@@ -3,13 +3,26 @@ import { useIcon } from "@wq/react";
|
|
|
3
3
|
import { List } from "react-native-paper";
|
|
4
4
|
import PropTypes from "prop-types";
|
|
5
5
|
|
|
6
|
-
export default function ListItem({
|
|
6
|
+
export default function ListItem({
|
|
7
|
+
children,
|
|
8
|
+
description,
|
|
9
|
+
icon,
|
|
10
|
+
dense,
|
|
11
|
+
style,
|
|
12
|
+
onClick,
|
|
13
|
+
...rest
|
|
14
|
+
}) {
|
|
7
15
|
const Icon = useIcon(icon);
|
|
8
16
|
return (
|
|
9
17
|
<List.Item
|
|
10
18
|
title={children}
|
|
11
19
|
description={description}
|
|
12
20
|
left={Icon ? (props) => <List.Icon icon={Icon} {...props} /> : null}
|
|
21
|
+
onPress={onClick}
|
|
22
|
+
style={{
|
|
23
|
+
...(dense && { paddingTop: 4, paddingBottom: 4 }),
|
|
24
|
+
...style,
|
|
25
|
+
}}
|
|
13
26
|
{...rest}
|
|
14
27
|
/>
|
|
15
28
|
);
|
|
@@ -19,4 +32,7 @@ ListItem.propTypes = {
|
|
|
19
32
|
children: PropTypes.node,
|
|
20
33
|
description: PropTypes.node,
|
|
21
34
|
icon: PropTypes.string,
|
|
35
|
+
dense: PropTypes.bool,
|
|
36
|
+
style: PropTypes.object,
|
|
37
|
+
onClick: PropTypes.func,
|
|
22
38
|
};
|
package/src/components/Popup.js
CHANGED
|
@@ -1,3 +1,19 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Modal, Portal } from "react-native-paper";
|
|
3
|
+
import PropTypes from "prop-types";
|
|
4
|
+
|
|
5
|
+
export default function Popup({ open, onClose, children, ...rest }) {
|
|
6
|
+
return (
|
|
7
|
+
<Portal>
|
|
8
|
+
<Modal visible={open} onDismiss={onClose} {...rest}>
|
|
9
|
+
{children}
|
|
10
|
+
</Modal>
|
|
11
|
+
</Portal>
|
|
12
|
+
);
|
|
3
13
|
}
|
|
14
|
+
|
|
15
|
+
Popup.propTypes = {
|
|
16
|
+
open: PropTypes.bool,
|
|
17
|
+
onClose: PropTypes.func,
|
|
18
|
+
children: PropTypes.node,
|
|
19
|
+
};
|
|
@@ -1,3 +1,26 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { RadioButton as PaperRadioButton, useTheme } from "react-native-paper";
|
|
3
|
+
import PropTypes from "prop-types";
|
|
4
|
+
|
|
5
|
+
const STATUSES = {
|
|
6
|
+
true: "checked",
|
|
7
|
+
false: "unchecked",
|
|
8
|
+
undefined: "unchecked",
|
|
9
|
+
null: "unchecked",
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export default function RadioButton({ checked, color, ...rest }) {
|
|
13
|
+
const status = STATUSES[checked],
|
|
14
|
+
theme = useTheme();
|
|
15
|
+
if (color === "primary") {
|
|
16
|
+
color = theme.colors.primary;
|
|
17
|
+
} else if (color === "secondary") {
|
|
18
|
+
color = theme.colors.accent;
|
|
19
|
+
}
|
|
20
|
+
return <PaperRadioButton status={status} {...rest} />;
|
|
3
21
|
}
|
|
22
|
+
|
|
23
|
+
RadioButton.propTypes = {
|
|
24
|
+
checked: PropTypes.bool,
|
|
25
|
+
color: PropTypes.string,
|
|
26
|
+
};
|
|
@@ -1,3 +1,94 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import React, { useState, useEffect } from "react";
|
|
2
|
+
import { useComponents } from "@wq/react";
|
|
3
|
+
import { View } from "react-native";
|
|
4
|
+
import { useTheme } from "react-native-paper";
|
|
5
|
+
import { useMinWidth } from "../hooks.js";
|
|
6
|
+
import PropTypes from "prop-types";
|
|
7
|
+
|
|
8
|
+
export default function SidePanel({
|
|
9
|
+
anchor: anchorSpec = "top-left",
|
|
10
|
+
children,
|
|
11
|
+
compactChildren,
|
|
12
|
+
onChange,
|
|
13
|
+
}) {
|
|
14
|
+
const mobile = !useMinWidth(900),
|
|
15
|
+
theme = useTheme(),
|
|
16
|
+
anchor = anchorSpec.endsWith("right") ? "right" : "left",
|
|
17
|
+
vAnchor = anchorSpec.startsWith("bottom") ? "bottom" : "top",
|
|
18
|
+
[open, setOpen] = useState(!mobile),
|
|
19
|
+
{ IconButton } = useComponents(),
|
|
20
|
+
drawerStyle = {},
|
|
21
|
+
iconStyle = {};
|
|
22
|
+
|
|
23
|
+
drawerStyle.zIndex = 1000;
|
|
24
|
+
drawerStyle.width = open ? 280 : 50;
|
|
25
|
+
drawerStyle.borderColor = "rgba(0, 0, 0, 0.12)";
|
|
26
|
+
|
|
27
|
+
if (mobile && !open) {
|
|
28
|
+
drawerStyle.backgroundColor = theme.colors.background;
|
|
29
|
+
drawerStyle.position = "absolute";
|
|
30
|
+
if (vAnchor === "bottom") {
|
|
31
|
+
drawerStyle.bottom = 0;
|
|
32
|
+
drawerStyle.borderTopWidth = 1;
|
|
33
|
+
} else {
|
|
34
|
+
drawerStyle.top = 0;
|
|
35
|
+
drawerStyle.borderBottomWidth = 1;
|
|
36
|
+
}
|
|
37
|
+
if (anchor === "right") {
|
|
38
|
+
drawerStyle.right = 1;
|
|
39
|
+
} else {
|
|
40
|
+
drawerStyle.left = 1;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (anchor === "right") {
|
|
45
|
+
iconStyle.transform = [{ rotate: "180deg" }];
|
|
46
|
+
drawerStyle.borderLeftWidth = 1;
|
|
47
|
+
} else {
|
|
48
|
+
drawerStyle.borderRightWidth = 1;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
useEffect(() => {
|
|
52
|
+
if (onChange) {
|
|
53
|
+
onChange(open);
|
|
54
|
+
}
|
|
55
|
+
}, [open, onChange]);
|
|
56
|
+
|
|
57
|
+
return (
|
|
58
|
+
<View style={drawerStyle}>
|
|
59
|
+
{open ? (
|
|
60
|
+
<View
|
|
61
|
+
style={{
|
|
62
|
+
display: "flex",
|
|
63
|
+
flexDirection: "row",
|
|
64
|
+
position: "sticky",
|
|
65
|
+
top: 0,
|
|
66
|
+
zIndex: 100,
|
|
67
|
+
}}
|
|
68
|
+
>
|
|
69
|
+
{anchor === "left" && <View style={{ flex: 1 }} />}
|
|
70
|
+
<IconButton
|
|
71
|
+
icon="panel-close"
|
|
72
|
+
style={iconStyle}
|
|
73
|
+
onClick={() => setOpen(false)}
|
|
74
|
+
/>
|
|
75
|
+
{anchor === "right" && <View style={{ flex: 1 }} />}
|
|
76
|
+
</View>
|
|
77
|
+
) : (
|
|
78
|
+
<IconButton
|
|
79
|
+
icon="panel-open"
|
|
80
|
+
style={iconStyle}
|
|
81
|
+
onClick={() => setOpen(true)}
|
|
82
|
+
/>
|
|
83
|
+
)}
|
|
84
|
+
{open ? children : compactChildren}
|
|
85
|
+
</View>
|
|
86
|
+
);
|
|
3
87
|
}
|
|
88
|
+
|
|
89
|
+
SidePanel.propTypes = {
|
|
90
|
+
children: PropTypes.node,
|
|
91
|
+
compactChildren: PropTypes.node,
|
|
92
|
+
onChange: PropTypes.func,
|
|
93
|
+
anchor: PropTypes.string,
|
|
94
|
+
};
|
package/src/components/Switch.js
CHANGED
|
@@ -1,3 +1,18 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Switch as PaperSwitch, useTheme } from "react-native-paper";
|
|
3
|
+
import PropTypes from "prop-types";
|
|
4
|
+
|
|
5
|
+
export default function Switch({ checked: value, color, ...rest }) {
|
|
6
|
+
const theme = useTheme();
|
|
7
|
+
if (color === "primary") {
|
|
8
|
+
color = theme.colors.primary;
|
|
9
|
+
} else if (color === "secondary") {
|
|
10
|
+
color = theme.colors.accent;
|
|
11
|
+
}
|
|
12
|
+
return <PaperSwitch value={value} {...rest} />;
|
|
3
13
|
}
|
|
14
|
+
|
|
15
|
+
Switch.propTypes = {
|
|
16
|
+
checked: PropTypes.bool,
|
|
17
|
+
color: PropTypes.string,
|
|
18
|
+
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import React, { useState } from "react";
|
|
2
|
+
import { useIconComponents } from "@wq/react";
|
|
3
|
+
import { View } from "react-native";
|
|
4
|
+
import { SegmentedButtons } from "react-native-paper";
|
|
5
|
+
import PropTypes from "prop-types";
|
|
6
|
+
|
|
7
|
+
export default function TabGroup({ children, style, ...rest }) {
|
|
8
|
+
const tabs = React.Children.toArray(children),
|
|
9
|
+
[value, setValue] = useState(tabs[0].props.value),
|
|
10
|
+
activeTab = tabs.find((tab) => tab.props.value === value),
|
|
11
|
+
handleChange = (tab) => setValue(tab),
|
|
12
|
+
icons = useIconComponents(),
|
|
13
|
+
buttons = tabs.map((tab) => ({
|
|
14
|
+
value: tab.props.value,
|
|
15
|
+
label: tab.props.label,
|
|
16
|
+
icon: icons[tab.props.icon],
|
|
17
|
+
}));
|
|
18
|
+
|
|
19
|
+
return (
|
|
20
|
+
<View style={{ flex: 1, display: "flex", flexDirection: "column" }}>
|
|
21
|
+
<SegmentedButtons
|
|
22
|
+
value={value}
|
|
23
|
+
onValueChange={handleChange}
|
|
24
|
+
buttons={buttons}
|
|
25
|
+
style={{ padding: 8, ...style }}
|
|
26
|
+
{...rest}
|
|
27
|
+
/>
|
|
28
|
+
<View style={{ flex: 1, display: "flex", flexDirection: "column" }}>
|
|
29
|
+
{activeTab && activeTab.props.children}
|
|
30
|
+
</View>
|
|
31
|
+
</View>
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
TabGroup.propTypes = {
|
|
36
|
+
children: PropTypes.node,
|
|
37
|
+
style: PropTypes.object,
|
|
38
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import PropTypes from "prop-types";
|
|
3
|
+
|
|
4
|
+
export default function TabItem({ value, icon, label, children }) {
|
|
5
|
+
/* eslint no-unused-vars: off */
|
|
6
|
+
|
|
7
|
+
// All rendering handled by TabGroup
|
|
8
|
+
return null;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
TabItem.propTypes = {
|
|
12
|
+
value: PropTypes.string,
|
|
13
|
+
icon: PropTypes.string,
|
|
14
|
+
label: PropTypes.string,
|
|
15
|
+
children: PropTypes.node,
|
|
16
|
+
};
|
|
@@ -1,3 +1,25 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { View } from "react-native";
|
|
1
3
|
import { DataTable } from "react-native-paper";
|
|
4
|
+
import PropTypes from "prop-types";
|
|
2
5
|
|
|
3
|
-
export default
|
|
6
|
+
export default function TableCell({ interactive, children, ...rest }) {
|
|
7
|
+
const Cell = interactive ? InteractiveCell : DataTable.Cell;
|
|
8
|
+
return <Cell {...rest}>{children}</Cell>;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function InteractiveCell(props) {
|
|
12
|
+
return (
|
|
13
|
+
<View
|
|
14
|
+
style={{
|
|
15
|
+
flex: 1,
|
|
16
|
+
flexDirection: "row",
|
|
17
|
+
alignItems: "center",
|
|
18
|
+
...props.style,
|
|
19
|
+
}}
|
|
20
|
+
{...props}
|
|
21
|
+
/>
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
TableCell.propTypes = { interactive: PropTypes.bool, children: PropTypes.node };
|