@ledgerhq/native-ui 0.16.0 → 0.17.0-recover-staging.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/lib/components/Layout/Divider/index.d.ts +5 -9
- package/lib/components/Layout/Divider/index.js +11 -1
- package/lib/components/Layout/List/VerticalTimeline/TimelineIndicator.d.ts +6 -1
- package/lib/components/Layout/List/VerticalTimeline/TimelineIndicator.js +39 -21
- package/lib/components/Layout/List/VerticalTimeline/TimelineItem.d.ts +2 -1
- package/lib/components/Layout/List/VerticalTimeline/TimelineItem.js +21 -24
- package/lib/components/Layout/List/VerticalTimeline/index.d.ts +11 -2
- package/lib/components/Layout/List/VerticalTimeline/index.js +23 -3
- package/lib/components/message/ContinueOnDevice/index.d.ts +9 -0
- package/lib/components/message/ContinueOnDevice/index.js +12 -0
- package/lib/components/message/index.d.ts +1 -0
- package/lib/components/message/index.js +1 -0
- package/package.json +5 -1
|
@@ -1,10 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
display?: string | undefined;
|
|
7
|
-
position?: string | undefined;
|
|
8
|
-
maxHeight?: string | number | undefined;
|
|
9
|
-
}, never>;
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { FlexBoxProps } from "../Flex";
|
|
3
|
+
declare const Divider: React.FC<FlexBoxProps & {
|
|
4
|
+
text?: string;
|
|
5
|
+
}>;
|
|
10
6
|
export default Divider;
|
|
@@ -1,8 +1,18 @@
|
|
|
1
|
+
import React from "react";
|
|
1
2
|
import Flex from "../Flex";
|
|
2
3
|
import styled from "styled-components/native";
|
|
3
|
-
|
|
4
|
+
import { Text } from "../../..";
|
|
5
|
+
const DividerBase = styled(Flex).attrs((p) => ({
|
|
4
6
|
my: p.my || 4,
|
|
5
7
|
height: 1,
|
|
6
8
|
backgroundColor: "neutral.c40",
|
|
7
9
|
})) ``;
|
|
10
|
+
const Divider = (props) => {
|
|
11
|
+
if (!props.text)
|
|
12
|
+
return React.createElement(DividerBase, Object.assign({}, props));
|
|
13
|
+
return (React.createElement(Flex, Object.assign({}, props, { flexDirection: "row", alignItems: "center" }),
|
|
14
|
+
React.createElement(DividerBase, { flex: 1 }),
|
|
15
|
+
React.createElement(Text, { variant: "bodyLineHeight", color: "neutral.c60", mx: 6 }, props.text),
|
|
16
|
+
React.createElement(DividerBase, { flex: 1 })));
|
|
17
|
+
};
|
|
8
18
|
export default Divider;
|
|
@@ -5,5 +5,10 @@ export type Props = FlexProps & {
|
|
|
5
5
|
status: ItemStatus;
|
|
6
6
|
isFirstItem?: boolean;
|
|
7
7
|
isLastItem?: boolean;
|
|
8
|
+
topHeight?: number;
|
|
8
9
|
};
|
|
9
|
-
|
|
10
|
+
declare function TimelineIndicator({ status, isFirstItem, isLastItem, topHeight, ...props }: Props): JSX.Element;
|
|
11
|
+
declare namespace TimelineIndicator {
|
|
12
|
+
var topSegmentDefaultHeight: number;
|
|
13
|
+
}
|
|
14
|
+
export default TimelineIndicator;
|
|
@@ -10,23 +10,40 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
10
10
|
return t;
|
|
11
11
|
};
|
|
12
12
|
import React from "react";
|
|
13
|
+
import { Dimensions, PixelRatio, Platform, StyleSheet } from "react-native";
|
|
13
14
|
import { CircledCheckSolidMedium } from "@ledgerhq/icons-ui/native";
|
|
14
15
|
import styled, { useTheme } from "styled-components/native";
|
|
16
|
+
import Svg, { Line } from "react-native-svg";
|
|
15
17
|
import Flex from "../../Flex";
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
18
|
+
const dashLength = 4;
|
|
19
|
+
const linesWidth = 2;
|
|
20
|
+
/**
|
|
21
|
+
* We have to set a fixed size for the lines (and then they get clipped with overflow:hidden)
|
|
22
|
+
* because their real height is dynamic (depends on the height of the step) and
|
|
23
|
+
* there seems to be no way to have that height being dynamic without having the
|
|
24
|
+
* scaling effect affecting the length of the stroke dash (the "- - - ").
|
|
25
|
+
* This is kind of a trick but seemingly the only way to have a nice stroke dash
|
|
26
|
+
**/
|
|
27
|
+
const linesLength = 5000;
|
|
28
|
+
const TopSegmentSvg = ({ status, hidden, height }) => {
|
|
29
|
+
const theme = useTheme();
|
|
30
|
+
const strokeColor = status === "inactive" ? theme.colors.neutral.c50 : theme.colors.primary.c80;
|
|
31
|
+
const strokeDashArray = status === "inactive" ? `${dashLength}` : undefined;
|
|
32
|
+
return (React.createElement(Flex, { height: height, width: "100%", overflow: "hidden" },
|
|
33
|
+
React.createElement(Flex, { style: StyleSheet.absoluteFillObject, alignItems: "center" },
|
|
34
|
+
React.createElement(Svg, { height: linesLength, width: linesWidth, viewBox: `0 0 ${linesWidth} ${linesLength}`, preserveAspectRatio: "xMinYMin slice" },
|
|
35
|
+
React.createElement(Line, { x1: "0", y1: "0", x2: "0", y2: "100", strokeWidth: hidden ? 0 : 2 * linesWidth, stroke: strokeColor, strokeDasharray: strokeDashArray })))));
|
|
36
|
+
};
|
|
37
|
+
const topSegmentDefaultHeight = Platform.OS === "android" ? 23 : 21; // difference due to how borders are drawn in android
|
|
38
|
+
const BottomSegmentSvg = ({ status, hidden }) => {
|
|
39
|
+
const theme = useTheme();
|
|
40
|
+
const strokeColor = status === "completed" ? theme.colors.primary.c80 : theme.colors.neutral.c50;
|
|
41
|
+
const strokeDashArray = status === "completed" ? undefined : `${dashLength}`;
|
|
42
|
+
return (React.createElement(Flex, { flex: 1, width: "100%", style: { transform: [{ scaleY: -1 }] }, overflow: "hidden" },
|
|
43
|
+
React.createElement(Flex, { style: StyleSheet.absoluteFillObject, alignItems: "center" },
|
|
44
|
+
React.createElement(Svg, { height: 2 * Dimensions.get("screen").height, width: linesWidth, viewBox: `0 0 ${linesWidth} ${linesLength}`, preserveAspectRatio: "xMinYMin slice" },
|
|
45
|
+
React.createElement(Line, { x1: "0", y1: "0", x2: "0", y2: "100%", strokeWidth: hidden ? 0 : 2 * linesWidth, stroke: strokeColor, strokeDasharray: strokeDashArray, strokeDashoffset: `${dashLength}` })))));
|
|
46
|
+
};
|
|
30
47
|
const getIconBackground = (theme, status, isLastItem) => {
|
|
31
48
|
if (status === "completed") {
|
|
32
49
|
return "transparent";
|
|
@@ -48,20 +65,21 @@ const getIconBorder = (theme, status, isLastItem) => {
|
|
|
48
65
|
}
|
|
49
66
|
return theme.colors.primary.c80;
|
|
50
67
|
};
|
|
51
|
-
const
|
|
68
|
+
const CenterCircle = styled(Flex) `
|
|
52
69
|
border-radius: 9999px;
|
|
53
|
-
width:
|
|
54
|
-
height:
|
|
70
|
+
width: 16px;
|
|
71
|
+
height: 16px;
|
|
55
72
|
background: ${(p) => getIconBackground(p.theme, p.status, p.isLastItem)};
|
|
56
73
|
border: 2px solid ${(p) => getIconBorder(p.theme, p.status, p.isLastItem)};
|
|
57
74
|
align-items: center;
|
|
58
75
|
justify-content: center;
|
|
59
76
|
`;
|
|
60
77
|
export default function TimelineIndicator(_a) {
|
|
61
|
-
var { status, isFirstItem, isLastItem } = _a, props = __rest(_a, ["status", "isFirstItem", "isLastItem"]);
|
|
78
|
+
var { status, isFirstItem, isLastItem, topHeight } = _a, props = __rest(_a, ["status", "isFirstItem", "isLastItem", "topHeight"]);
|
|
62
79
|
const { colors } = useTheme();
|
|
63
80
|
return (React.createElement(Flex, Object.assign({ flexDirection: "column", alignItems: "center" }, props),
|
|
64
|
-
React.createElement(
|
|
65
|
-
React.createElement(
|
|
66
|
-
React.createElement(
|
|
81
|
+
React.createElement(TopSegmentSvg, { status: status, hidden: isFirstItem, height: PixelRatio.roundToNearestPixel(topHeight || topSegmentDefaultHeight) }),
|
|
82
|
+
React.createElement(CenterCircle, { status: status, isLastItem: isLastItem }, status === "completed" && (React.createElement(CircledCheckSolidMedium, { color: isLastItem ? colors.success.c100 : colors.primary.c80, size: 20 }))),
|
|
83
|
+
React.createElement(BottomSegmentSvg, { status: status, hidden: isLastItem })));
|
|
67
84
|
}
|
|
85
|
+
TimelineIndicator.topSegmentDefaultHeight = topSegmentDefaultHeight;
|
|
@@ -7,5 +7,6 @@ export type Props = {
|
|
|
7
7
|
isLastItem?: boolean;
|
|
8
8
|
setActiveIndex?: (_: number) => void;
|
|
9
9
|
index: number;
|
|
10
|
+
withExtraMarginOnActiveStep?: boolean;
|
|
10
11
|
};
|
|
11
|
-
export default function TimelineItem({ item, formatEstimatedTime, isFirstItem, isLastItem, setActiveIndex, index, }: Props): JSX.Element;
|
|
12
|
+
export default function TimelineItem({ item, formatEstimatedTime, isFirstItem, isLastItem, setActiveIndex, index, withExtraMarginOnActiveStep, }: Props): JSX.Element;
|
|
@@ -1,47 +1,42 @@
|
|
|
1
1
|
import React, { useCallback } from "react";
|
|
2
2
|
import { Pressable } from "react-native";
|
|
3
3
|
import Animated, { useAnimatedStyle, useSharedValue, withTiming } from "react-native-reanimated";
|
|
4
|
-
import styled from "styled-components/native";
|
|
4
|
+
import styled, { useTheme } from "styled-components/native";
|
|
5
5
|
import Flex from "../../Flex";
|
|
6
6
|
import Text from "../../../Text";
|
|
7
7
|
import Tag from "../../../tags/Tag";
|
|
8
8
|
import TimelineIndicator from "./TimelineIndicator";
|
|
9
|
-
const getContainerBackground = (theme, status
|
|
10
|
-
if (
|
|
11
|
-
return
|
|
12
|
-
}
|
|
13
|
-
else if (status === "completed") {
|
|
14
|
-
return theme.colors.primary.c20;
|
|
9
|
+
const getContainerBackground = (theme, status) => {
|
|
10
|
+
if (status === "completed") {
|
|
11
|
+
return "transparent";
|
|
15
12
|
}
|
|
16
13
|
else if (status === "active") {
|
|
17
14
|
return theme.colors.neutral.c20;
|
|
18
15
|
}
|
|
19
|
-
return
|
|
16
|
+
return "transparent";
|
|
20
17
|
};
|
|
21
18
|
const getContainerBorder = (theme, status, isLastItem) => {
|
|
22
|
-
if (
|
|
23
|
-
return
|
|
19
|
+
if (status === "completed") {
|
|
20
|
+
return "transparent";
|
|
24
21
|
}
|
|
25
22
|
else if (isLastItem && status === "active") {
|
|
26
23
|
return theme.colors.success.c100;
|
|
27
24
|
}
|
|
28
|
-
else if (status === "completed") {
|
|
29
|
-
return theme.colors.primary.c20;
|
|
30
|
-
}
|
|
31
25
|
else if (status === "active") {
|
|
32
|
-
return theme.colors.
|
|
26
|
+
return theme.colors.neutral.c40;
|
|
33
27
|
}
|
|
34
|
-
return
|
|
28
|
+
return "transparent";
|
|
35
29
|
};
|
|
36
30
|
const Container = styled(Flex) `
|
|
37
31
|
flex: 1;
|
|
38
32
|
border-radius: ${(p) => p.theme.radii[2]}px;
|
|
39
|
-
background: ${(p) => getContainerBackground(p.theme, p.status
|
|
33
|
+
background: ${(p) => getContainerBackground(p.theme, p.status)};
|
|
40
34
|
border: 1px solid ${(p) => getContainerBorder(p.theme, p.status, p.isLastItem)};
|
|
41
35
|
padding: 20px 16px;
|
|
42
36
|
`;
|
|
43
|
-
export default function TimelineItem({ item, formatEstimatedTime, isFirstItem, isLastItem, setActiveIndex, index, }) {
|
|
37
|
+
export default function TimelineItem({ item, formatEstimatedTime, isFirstItem, isLastItem, setActiveIndex, index, withExtraMarginOnActiveStep, }) {
|
|
44
38
|
var _a;
|
|
39
|
+
const theme = useTheme();
|
|
45
40
|
/**
|
|
46
41
|
* Having an initial value of null will prevent having "height: 0" before the
|
|
47
42
|
* initial call of onLayout.
|
|
@@ -69,14 +64,16 @@ export default function TimelineItem({ item, formatEstimatedTime, isFirstItem, i
|
|
|
69
64
|
}, [setActiveIndex, index]);
|
|
70
65
|
return (React.createElement(Pressable, { onPress: handlePress },
|
|
71
66
|
React.createElement(Flex, { flexDirection: "row" },
|
|
72
|
-
React.createElement(TimelineIndicator, { status: item.status, isFirstItem: isFirstItem, isLastItem: isLastItem, mr: 4
|
|
73
|
-
|
|
67
|
+
React.createElement(TimelineIndicator, { status: item.status, isFirstItem: isFirstItem, isLastItem: isLastItem, mr: 4, topHeight: withExtraMarginOnActiveStep && !isFirstItem && item.status === "active"
|
|
68
|
+
? TimelineIndicator.topSegmentDefaultHeight + theme.space[4]
|
|
69
|
+
: undefined }),
|
|
70
|
+
React.createElement(Container, { status: item.status, isLastItem: isLastItem, mt: withExtraMarginOnActiveStep && !isFirstItem && item.status === "active" ? 4 : 0, mb: withExtraMarginOnActiveStep && !isLastItem && item.status === "active" ? 4 : 0 },
|
|
74
71
|
React.createElement(Flex, { flexDirection: "row", justifyContent: "space-between" },
|
|
75
|
-
React.createElement(Text, { variant: "body", flexShrink: 1, color: item.status === "
|
|
76
|
-
? "
|
|
77
|
-
:
|
|
78
|
-
? "
|
|
79
|
-
: "
|
|
72
|
+
React.createElement(Text, { variant: "body", fontWeight: "semiBold", flexShrink: 1, color: item.status === "completed" && isLastItem
|
|
73
|
+
? "success.c80"
|
|
74
|
+
: item.status === "active"
|
|
75
|
+
? "primary.c80"
|
|
76
|
+
: "neutral.c70" }, item.status === "completed" ? (_a = item.doneTitle) !== null && _a !== void 0 ? _a : item.title : item.title),
|
|
80
77
|
(item === null || item === void 0 ? void 0 : item.estimatedTime) && item.status === "active" && (React.createElement(Tag, null, formatEstimatedTime
|
|
81
78
|
? formatEstimatedTime(item.estimatedTime)
|
|
82
79
|
: `${item.estimatedTime / 60} min`))),
|
|
@@ -1,13 +1,22 @@
|
|
|
1
|
-
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { BaseTextProps } from "../../../Text";
|
|
2
3
|
import { BaseStyledProps } from "src/components/styled";
|
|
3
4
|
import { Item } from "../types";
|
|
4
5
|
export type Props = BaseStyledProps & {
|
|
5
6
|
steps?: Item[];
|
|
6
7
|
formatEstimatedTime?: (_: number) => string;
|
|
7
8
|
setActiveIndex?: (arg0: number) => void;
|
|
9
|
+
header?: React.ReactNode;
|
|
10
|
+
/**
|
|
11
|
+
* Should the scroll view automatically scroll to the active step.
|
|
12
|
+
* Defaults to true.
|
|
13
|
+
* */
|
|
14
|
+
autoScroll?: boolean;
|
|
8
15
|
};
|
|
9
|
-
declare function VerticalTimeline({ steps, formatEstimatedTime, setActiveIndex, ...props }: Props): JSX.Element;
|
|
16
|
+
declare function VerticalTimeline({ steps, formatEstimatedTime, setActiveIndex, header, autoScroll, ...props }: Props): JSX.Element;
|
|
10
17
|
declare namespace VerticalTimeline {
|
|
18
|
+
var BodyText: React.FC<BaseTextProps>;
|
|
19
|
+
var SubtitleText: React.FC<BaseTextProps>;
|
|
11
20
|
var ItemStatus: typeof import("../types").ItemStatus;
|
|
12
21
|
}
|
|
13
22
|
export default VerticalTimeline;
|
|
@@ -9,12 +9,32 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
9
9
|
}
|
|
10
10
|
return t;
|
|
11
11
|
};
|
|
12
|
-
import React from "react";
|
|
12
|
+
import React, { useRef, useCallback } from "react";
|
|
13
|
+
import { ScrollView, View } from "react-native";
|
|
13
14
|
import TimelineItem from "./TimelineItem";
|
|
14
15
|
import Flex from "../../Flex";
|
|
16
|
+
import Text from "../../../Text";
|
|
15
17
|
import { ItemStatus } from "../types";
|
|
16
18
|
export default function VerticalTimeline(_a) {
|
|
17
|
-
var { steps, formatEstimatedTime, setActiveIndex } = _a, props = __rest(_a, ["steps", "formatEstimatedTime", "setActiveIndex"]);
|
|
18
|
-
|
|
19
|
+
var { steps, formatEstimatedTime, setActiveIndex, header, autoScroll = true } = _a, props = __rest(_a, ["steps", "formatEstimatedTime", "setActiveIndex", "header", "autoScroll"]);
|
|
20
|
+
const scrollViewRef = useRef(null);
|
|
21
|
+
const stepsContainerLayout = useRef();
|
|
22
|
+
const onStepsContainerLayout = useCallback((evt) => {
|
|
23
|
+
stepsContainerLayout.current = evt.nativeEvent.layout;
|
|
24
|
+
}, []);
|
|
25
|
+
const onActiveStepLayout = useCallback((evt) => {
|
|
26
|
+
if (!stepsContainerLayout.current || !scrollViewRef.current)
|
|
27
|
+
return;
|
|
28
|
+
const { layout } = evt.nativeEvent;
|
|
29
|
+
scrollViewRef.current.scrollTo({ x: 0, y: stepsContainerLayout.current.y + layout.y });
|
|
30
|
+
}, []);
|
|
31
|
+
return (React.createElement(ScrollView, { ref: scrollViewRef, onLayout: onStepsContainerLayout },
|
|
32
|
+
header,
|
|
33
|
+
React.createElement(Flex, Object.assign({}, props, { onLayout: onStepsContainerLayout, flexDirection: "column" }), steps === null || steps === void 0 ? void 0 : steps.map((step, index) => (React.createElement(View, { onLayout: autoScroll && step.status === "active" ? onActiveStepLayout : undefined },
|
|
34
|
+
React.createElement(TimelineItem, { key: step.title, item: step, formatEstimatedTime: formatEstimatedTime, isFirstItem: index === 0, isLastItem: index === steps.length - 1, setActiveIndex: setActiveIndex, index: index })))))));
|
|
19
35
|
}
|
|
36
|
+
const SubtitleText = (props) => (React.createElement(Text, Object.assign({ variant: "body", fontWeight: "semiBold", color: "neutral.c100", mb: 3 }, props)));
|
|
37
|
+
const BodyText = (props) => (React.createElement(Text, Object.assign({ variant: "bodyLineHeight", fontWeight: "medium", color: "neutral.c80" }, props)));
|
|
38
|
+
VerticalTimeline.BodyText = BodyText;
|
|
39
|
+
VerticalTimeline.SubtitleText = SubtitleText;
|
|
20
40
|
VerticalTimeline.ItemStatus = ItemStatus;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import Divider from "../../Layout/Divider";
|
|
3
|
+
import Flex from "../../Layout/Flex";
|
|
4
|
+
import Text from "../../Text";
|
|
5
|
+
const ContinueOnDevice = ({ Icon, text, withTopDivider = true }) => {
|
|
6
|
+
return (React.createElement(Flex, null,
|
|
7
|
+
withTopDivider ? React.createElement(Divider, { my: 6 }) : null,
|
|
8
|
+
React.createElement(Flex, { flexDirection: "row", alignItems: "center", flexShrink: 1 },
|
|
9
|
+
React.createElement(Icon, { size: 48 }),
|
|
10
|
+
React.createElement(Text, { flex: 1, pl: 4, flexWrap: "wrap", variant: "body", fontWeight: "medium", color: "neutral.c100" }, text))));
|
|
11
|
+
};
|
|
12
|
+
export default ContinueOnDevice;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ledgerhq/native-ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.17.0-recover-staging.0",
|
|
4
4
|
"description": "Ledger Live - Mobile UI",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -25,6 +25,10 @@
|
|
|
25
25
|
},
|
|
26
26
|
"exports": {
|
|
27
27
|
".": "./lib/index.js",
|
|
28
|
+
"./lib/*": "./lib/*.js",
|
|
29
|
+
"./lib/*/": "./lib/*/index.js",
|
|
30
|
+
"./*": "./lib/*.js",
|
|
31
|
+
"./*/": "./lib/*/index.js",
|
|
28
32
|
"./": "./lib/",
|
|
29
33
|
"./package.json": "./package.json"
|
|
30
34
|
},
|