@ledgerhq/native-ui 0.23.3 → 0.23.4-nightly.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/lib/components/Form/TabSelector/index.d.ts +11 -0
- package/lib/components/Form/TabSelector/index.js +61 -0
- package/lib/components/Form/index.d.ts +1 -0
- package/lib/components/Form/index.js +1 -0
- package/lib/components/Layout/Modals/BaseModal/index.d.ts +4 -1
- package/lib/components/Layout/Modals/BaseModal/index.js +20 -3
- package/package.json +3 -3
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
interface TabSelectorProps<T extends string | number> {
|
|
3
|
+
options: T[];
|
|
4
|
+
selectedOption: T;
|
|
5
|
+
handleSelectOption: (option: T) => void;
|
|
6
|
+
labels: {
|
|
7
|
+
[key in T]: string;
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
export default function TabSelector<T extends string | number>({ options, selectedOption, handleSelectOption, labels, }: TabSelectorProps<T>): JSX.Element;
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import React, { useEffect } from "react";
|
|
2
|
+
import Text from "../../Text";
|
|
3
|
+
import Flex from "../../Layout/Flex";
|
|
4
|
+
import styled, { useTheme } from "styled-components/native";
|
|
5
|
+
import { TouchableOpacity } from "react-native";
|
|
6
|
+
import Animated, { useSharedValue, useAnimatedStyle, withSpring } from "react-native-reanimated";
|
|
7
|
+
const StyledTouchableOpacity = styled(TouchableOpacity) `
|
|
8
|
+
width: ${(p) => p.width}px;
|
|
9
|
+
flex: 1;
|
|
10
|
+
height: 100%;
|
|
11
|
+
`;
|
|
12
|
+
const StyledFlex = styled(Flex) `
|
|
13
|
+
height: 100%;
|
|
14
|
+
justify-content: center;
|
|
15
|
+
align-items: center;
|
|
16
|
+
`;
|
|
17
|
+
const StyledText = styled(Text) `
|
|
18
|
+
line-height: 14.52px;
|
|
19
|
+
overflow: visible;
|
|
20
|
+
text-align: center;
|
|
21
|
+
font-size: 12px;
|
|
22
|
+
color: ${(p) => p.isSelected ? p.theme.colors.constant.black : p.theme.colors.opacityDefault.c50};
|
|
23
|
+
`;
|
|
24
|
+
const OptionButton = ({ option, selectedOption, handleSelectOption, label, width, }) => {
|
|
25
|
+
const isSelected = selectedOption === option;
|
|
26
|
+
return (React.createElement(StyledTouchableOpacity, { width: width, onPress: () => handleSelectOption(option) },
|
|
27
|
+
React.createElement(StyledFlex, { isSelected: isSelected },
|
|
28
|
+
React.createElement(StyledText, { fontWeight: "semiBold", isSelected: isSelected, numberOfLines: 1 }, label))));
|
|
29
|
+
};
|
|
30
|
+
export default function TabSelector({ options, selectedOption, handleSelectOption, labels, }) {
|
|
31
|
+
const { colors } = useTheme();
|
|
32
|
+
const longuestLabel = labels[options[0]].length > labels[options[1]].length ? options[0] : options[1];
|
|
33
|
+
const widthFactor = 8;
|
|
34
|
+
const margin = 20;
|
|
35
|
+
const width = labels[longuestLabel].length * widthFactor + margin;
|
|
36
|
+
const semiWidth = width / 2;
|
|
37
|
+
const translateX = useSharedValue(-semiWidth);
|
|
38
|
+
useEffect(() => {
|
|
39
|
+
translateX.value = withSpring(selectedOption === options[0] ? -semiWidth : semiWidth, {
|
|
40
|
+
damping: 30,
|
|
41
|
+
stiffness: 80,
|
|
42
|
+
});
|
|
43
|
+
}, [selectedOption, translateX, options]);
|
|
44
|
+
const animatedStyle = useAnimatedStyle(() => {
|
|
45
|
+
return {
|
|
46
|
+
transform: [{ translateX: translateX.value }],
|
|
47
|
+
};
|
|
48
|
+
});
|
|
49
|
+
return (React.createElement(Flex, { flexDirection: "row", justifyContent: "center", alignItems: "center", width: width * 2 + 4, height: "35px", borderRadius: "40px", bg: colors.opacityDefault.c05, position: "relative" },
|
|
50
|
+
React.createElement(Animated.View, { style: [
|
|
51
|
+
{
|
|
52
|
+
position: "absolute",
|
|
53
|
+
width: width - 2,
|
|
54
|
+
height: "90%",
|
|
55
|
+
backgroundColor: colors.primary.c80,
|
|
56
|
+
borderRadius: 40,
|
|
57
|
+
},
|
|
58
|
+
animatedStyle,
|
|
59
|
+
] }),
|
|
60
|
+
options.map((option) => (React.createElement(OptionButton, { width: width, key: option, option: option, selectedOption: selectedOption, handleSelectOption: handleSelectOption, label: labels[option] })))));
|
|
61
|
+
}
|
|
@@ -5,6 +5,7 @@ import { IconOrElementType } from "../../../Icon/type";
|
|
|
5
5
|
export type BaseModalProps = {
|
|
6
6
|
isOpen?: boolean;
|
|
7
7
|
onClose?: () => void;
|
|
8
|
+
onBack?: () => void;
|
|
8
9
|
modalStyle?: StyleProp<ViewStyle>;
|
|
9
10
|
safeContainerStyle?: StyleProp<ViewStyle>;
|
|
10
11
|
containerStyle?: StyleProp<ViewStyle>;
|
|
@@ -16,10 +17,12 @@ export type BaseModalProps = {
|
|
|
16
17
|
subtitle?: string;
|
|
17
18
|
children?: React.ReactNode;
|
|
18
19
|
noCloseButton?: boolean;
|
|
20
|
+
hasBackButton?: boolean;
|
|
19
21
|
CustomHeader?: React.ComponentType<{
|
|
20
22
|
children?: ReactNode;
|
|
21
23
|
}>;
|
|
22
24
|
} & Partial<ModalProps>;
|
|
23
25
|
export declare function ModalHeader({ Icon, iconColor, title, description, subtitle, }: Pick<BaseModalProps, "Icon" | "iconColor" | "title" | "description" | "subtitle">): React.ReactElement | null;
|
|
24
26
|
export declare function ModalHeaderCloseButton({ onClose, }: Pick<BaseModalProps, "onClose">): React.ReactElement;
|
|
25
|
-
export
|
|
27
|
+
export declare function ModalHeaderBackButton({ onBack, }: Pick<BaseModalProps, "onBack">): React.ReactElement;
|
|
28
|
+
export default function BaseModal({ isOpen, onClose, onBack, noCloseButton, hasBackButton, safeContainerStyle, containerStyle, modalStyle, preventBackdropClick, Icon, iconColor, title, description, subtitle, children, onModalHide, CustomHeader, ...rest }: BaseModalProps): React.ReactElement;
|
|
@@ -12,12 +12,13 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
12
12
|
import React, { useCallback } from "react";
|
|
13
13
|
import ReactNativeModal from "react-native-modal";
|
|
14
14
|
import styled from "styled-components/native";
|
|
15
|
+
import { TouchableOpacity } from "react-native";
|
|
15
16
|
import sizes from "../../../../helpers/getDeviceSize";
|
|
16
17
|
import Text from "../../../Text";
|
|
17
18
|
import { BoxedIcon } from "../../../Icon";
|
|
18
19
|
import { Flex } from "../../index";
|
|
19
20
|
import { space } from "styled-system";
|
|
20
|
-
import { Close } from "@ledgerhq/icons-ui/native";
|
|
21
|
+
import { Close, ArrowLeft } from "@ledgerhq/icons-ui/native";
|
|
21
22
|
import { useTheme } from "styled-components/native";
|
|
22
23
|
const { width, height } = sizes;
|
|
23
24
|
const SafeContainer = styled.SafeAreaView `
|
|
@@ -39,6 +40,12 @@ const CloseContainer = styled.View `
|
|
|
39
40
|
margin-bottom: ${(p) => p.theme.space[6]}px;
|
|
40
41
|
z-index: 10;
|
|
41
42
|
`;
|
|
43
|
+
const BackContainer = styled.View `
|
|
44
|
+
display: flex;
|
|
45
|
+
align-items: flex-start;
|
|
46
|
+
margin-bottom: ${(p) => p.theme.space[6]}px;
|
|
47
|
+
z-index: 10;
|
|
48
|
+
`;
|
|
42
49
|
const ClosePressableExtendedBounds = styled.TouchableOpacity.attrs({
|
|
43
50
|
p: 3,
|
|
44
51
|
}) `
|
|
@@ -76,8 +83,14 @@ export function ModalHeaderCloseButton({ onClose, }) {
|
|
|
76
83
|
React.createElement(ClosePressableExtendedBounds, { onPress: onClose, testID: "modal-close-button" },
|
|
77
84
|
React.createElement(Close, { color: colors.neutral.c100, size: "XS" }))));
|
|
78
85
|
}
|
|
86
|
+
export function ModalHeaderBackButton({ onBack, }) {
|
|
87
|
+
const { colors } = useTheme();
|
|
88
|
+
return (React.createElement(BackContainer, null,
|
|
89
|
+
React.createElement(TouchableOpacity, { onPress: onBack, testID: "modal-back-button" },
|
|
90
|
+
React.createElement(ArrowLeft, { color: colors.neutral.c100, size: "XS" }))));
|
|
91
|
+
}
|
|
79
92
|
export default function BaseModal(_a) {
|
|
80
|
-
var { isOpen, onClose = () => { }, noCloseButton, safeContainerStyle = {}, containerStyle = {}, modalStyle = {}, preventBackdropClick, Icon, iconColor, title, description, subtitle, children, onModalHide, CustomHeader } = _a, rest = __rest(_a, ["isOpen", "onClose", "noCloseButton", "safeContainerStyle", "containerStyle", "modalStyle", "preventBackdropClick", "Icon", "iconColor", "title", "description", "subtitle", "children", "onModalHide", "CustomHeader"]);
|
|
93
|
+
var { isOpen, onClose = () => { }, onBack = () => { }, noCloseButton, hasBackButton, safeContainerStyle = {}, containerStyle = {}, modalStyle = {}, preventBackdropClick, Icon, iconColor, title, description, subtitle, children, onModalHide, CustomHeader } = _a, rest = __rest(_a, ["isOpen", "onClose", "onBack", "noCloseButton", "hasBackButton", "safeContainerStyle", "containerStyle", "modalStyle", "preventBackdropClick", "Icon", "iconColor", "title", "description", "subtitle", "children", "onModalHide", "CustomHeader"]);
|
|
81
94
|
const backDropProps = preventBackdropClick
|
|
82
95
|
? {}
|
|
83
96
|
: {
|
|
@@ -96,7 +109,11 @@ export default function BaseModal(_a) {
|
|
|
96
109
|
React.createElement(SafeContainer, { style: safeContainerStyle },
|
|
97
110
|
CustomHeader && (React.createElement(CustomHeader, null, !noCloseButton && React.createElement(ModalHeaderCloseButton, { onClose: onClose }))),
|
|
98
111
|
React.createElement(Container, { style: containerStyle },
|
|
99
|
-
|
|
112
|
+
React.createElement(Flex, { flexDirection: "row", justifyContent: "space-between", width: "100%", alignItems: "center" },
|
|
113
|
+
!CustomHeader && onBack && hasBackButton && (React.createElement(Flex, { flex: 1, justifyContent: "flex-start" },
|
|
114
|
+
React.createElement(ModalHeaderBackButton, { onBack: onBack }))),
|
|
115
|
+
!CustomHeader && !noCloseButton && (React.createElement(Flex, { flex: 1, justifyContent: "flex-end" },
|
|
116
|
+
React.createElement(ModalHeaderCloseButton, { onClose: onClose })))),
|
|
100
117
|
React.createElement(ModalHeader, { Icon: Icon, iconColor: iconColor, title: title, description: description, subtitle: subtitle }),
|
|
101
118
|
React.createElement(ContentContainer, null, children)))));
|
|
102
119
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ledgerhq/native-ui",
|
|
3
|
-
"version": "0.23.
|
|
3
|
+
"version": "0.23.4-nightly.1",
|
|
4
4
|
"description": "Ledger Live - Mobile UI",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -40,8 +40,8 @@
|
|
|
40
40
|
"react-native-modal": "^13.0.0",
|
|
41
41
|
"rn-range-slider": "2.1.1",
|
|
42
42
|
"styled-system": "^5.1.5",
|
|
43
|
-
"@ledgerhq/crypto-icons-ui": "^1.4.0",
|
|
44
|
-
"@ledgerhq/icons-ui": "^0.7.
|
|
43
|
+
"@ledgerhq/crypto-icons-ui": "^1.4.1-nightly.0",
|
|
44
|
+
"@ledgerhq/icons-ui": "^0.7.3-nightly.0",
|
|
45
45
|
"@ledgerhq/ui-shared": "^0.2.1"
|
|
46
46
|
},
|
|
47
47
|
"peerDependencies": {
|