@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.
@@ -1,10 +1,6 @@
1
- /// <reference types="styled-components-react-native" />
2
- declare const Divider: import("styled-components").StyledComponent<typeof import("react-native").View, import("styled-components").DefaultTheme, import("styled-system").SpaceProps<Required<import("styled-system").Theme<import("styled-system").TLengthStyledSystem>>, string | number | symbol> & import("styled-system").FlexboxProps<Required<import("styled-system").Theme<import("styled-system").TLengthStyledSystem>>> & import("styled-system").PositionProps<Required<import("styled-system").Theme<import("styled-system").TLengthStyledSystem>>> & import("styled-system").ColorProps<Required<import("styled-system").Theme<import("styled-system").TLengthStyledSystem>>, string | number | symbol> & import("styled-system").LayoutProps<Required<import("styled-system").Theme<import("styled-system").TLengthStyledSystem>>> & import("styled-system").OverflowProps<Required<import("styled-system").Theme<import("styled-system").TLengthStyledSystem>>> & import("styled-system").BorderProps<Required<import("styled-system").Theme<import("styled-system").TLengthStyledSystem>>, import("csstype").Property.Border<import("styled-system").TLengthStyledSystem>> & import("styled-system").BackgroundProps<Required<import("styled-system").Theme<import("styled-system").TLengthStyledSystem>>, import("csstype").Property.Background<import("styled-system").TLengthStyledSystem>> & {
3
- columnGap?: string | number | undefined;
4
- rowGap?: string | number | undefined;
5
- color?: string | undefined;
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
- const Divider = styled(Flex).attrs((p) => ({
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
- export default function TimelineIndicator({ status, isFirstItem, isLastItem, ...props }: Props): JSX.Element;
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 TopSegment = styled(Flex) `
17
- height: 20px;
18
- border-width: ${(p) => (p.hidden ? 0 : 1)}px;
19
- border-style: solid;
20
- border-color: ${(p) => p.status === "inactive" ? p.theme.colors.neutral.c50 : p.theme.colors.primary.c80};
21
- background: ${(p) => p.status === "inactive" ? p.theme.colors.neutral.c50 : p.theme.colors.primary.c80};
22
- `;
23
- const BottomSegment = styled(Flex) `
24
- flex: 1;
25
- border-width: ${(p) => (p.hidden ? 0 : 1)}px;
26
- border-style: solid;
27
- border-color: ${(p) => p.status === "completed" ? p.theme.colors.primary.c80 : p.theme.colors.neutral.c50};
28
- background: ${(p) => p.status === "completed" ? p.theme.colors.primary.c80 : p.theme.colors.neutral.c50};
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 CenterSegment = styled(Flex) `
68
+ const CenterCircle = styled(Flex) `
52
69
  border-radius: 9999px;
53
- width: 20px;
54
- height: 20px;
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(TopSegment, { status: status, hidden: isFirstItem }),
65
- React.createElement(CenterSegment, { status: status, isLastItem: isLastItem }, status === "completed" && (React.createElement(CircledCheckSolidMedium, { color: isLastItem ? colors.success.c100 : colors.primary.c80, size: 24 }))),
66
- React.createElement(BottomSegment, { status: status, hidden: isLastItem })));
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, isLastItem) => {
10
- if (isLastItem && status === "completed") {
11
- return theme.colors.success.c30;
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 theme.colors.neutral.c30;
16
+ return "transparent";
20
17
  };
21
18
  const getContainerBorder = (theme, status, isLastItem) => {
22
- if (isLastItem && status === "completed") {
23
- return theme.colors.success.c30;
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.primary.c80;
26
+ return theme.colors.neutral.c40;
33
27
  }
34
- return theme.colors.neutral.c30;
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, p.isLastItem)};
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
- React.createElement(Container, { status: item.status, isLastItem: isLastItem, mb: 4 },
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 === "inactive"
76
- ? "neutral.c80"
77
- : isLastItem
78
- ? "success.c100"
79
- : "primary.c90" }, item.status === "completed" ? (_a = item.doneTitle) !== null && _a !== void 0 ? _a : item.title : item.title),
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
- /// <reference types="react" />
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
- return (React.createElement(Flex, Object.assign({}, props, { flexDirection: "column" }), steps === null || steps === void 0 ? void 0 : steps.map((step, index) => (React.createElement(TimelineItem, { key: step.title, item: step, formatEstimatedTime: formatEstimatedTime, isFirstItem: index === 0, isLastItem: index === steps.length - 1, setActiveIndex: setActiveIndex, index: index })))));
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,9 @@
1
+ import React from "react";
2
+ import { IconType } from "src/components/Icon/type";
3
+ type Props = {
4
+ Icon: IconType;
5
+ text: string;
6
+ withTopDivider?: boolean;
7
+ };
8
+ declare const ContinueOnDevice: React.FC<Props>;
9
+ export default ContinueOnDevice;
@@ -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;
@@ -1,3 +1,4 @@
1
1
  export { default as Alert } from "./Alert";
2
+ export { default as ContinueOnDevice } from "./ContinueOnDevice";
2
3
  export { default as Notification } from "./Notification";
3
4
  export { default as Log } from "./Log";
@@ -1,3 +1,4 @@
1
1
  export { default as Alert } from "./Alert";
2
+ export { default as ContinueOnDevice } from "./ContinueOnDevice";
2
3
  export { default as Notification } from "./Notification";
3
4
  export { default as Log } from "./Log";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ledgerhq/native-ui",
3
- "version": "0.16.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
  },