@ledgerhq/native-ui 0.1.1 → 0.5.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.
Files changed (79) hide show
  1. package/README.md +21 -21
  2. package/assets/icons.d.ts +1 -0
  3. package/assets/icons.js +1 -0
  4. package/assets/logos/LedgerLiveAltRegular.d.ts +0 -1
  5. package/assets/logos/LedgerLiveRegular.d.ts +0 -1
  6. package/components/Carousel/index.d.ts +45 -0
  7. package/components/Carousel/index.js +76 -0
  8. package/components/Form/Checkbox/index.d.ts +2 -2
  9. package/components/Form/Checkbox/index.js +5 -5
  10. package/components/Form/Input/BaseInput/index.d.ts +105 -9
  11. package/components/Form/Input/BaseInput/index.js +25 -17
  12. package/components/Form/Input/LegendInput/index.d.ts +14 -3
  13. package/components/Form/Input/LegendInput/index.js +4 -3
  14. package/components/Form/Input/NumberInput/index.d.ts +16 -4
  15. package/components/Form/Input/NumberInput/index.js +17 -9
  16. package/components/Form/Input/QrCodeInput/index.d.ts +15 -4
  17. package/components/Form/Input/QrCodeInput/index.js +5 -4
  18. package/components/Form/Input/SearchInput/index.d.ts +13 -2
  19. package/components/Form/Input/SearchInput/index.js +4 -3
  20. package/components/Form/SelectableList.d.ts +17 -0
  21. package/components/Form/SelectableList.js +32 -0
  22. package/components/Form/Slider/components.js +6 -6
  23. package/components/Form/Slider/index.d.ts +2 -2
  24. package/components/Form/Slider/index.js +1 -1
  25. package/components/Form/Slider/index.native.d.ts +0 -1
  26. package/components/Form/Slider/index.native.js +2 -2
  27. package/components/Form/Switch/index.d.ts +0 -1
  28. package/components/Form/Switch/index.js +4 -4
  29. package/components/Form/Toggle/index.d.ts +0 -1
  30. package/components/Form/index.d.ts +1 -0
  31. package/components/Form/index.js +1 -0
  32. package/components/Icon/IconBox/index.js +2 -2
  33. package/components/Layout/Box/index.d.ts +11 -0
  34. package/components/Layout/Box/index.js +3 -0
  35. package/components/Layout/Flex/index.d.ts +11 -12
  36. package/components/Layout/Flex/index.js +2 -8
  37. package/components/Layout/Modals/BaseModal/index.d.ts +2 -2
  38. package/components/Layout/Modals/BaseModal/index.js +7 -7
  39. package/components/Layout/ScrollContainerHeader/Header.d.ts +0 -1
  40. package/components/Layout/ScrollContainerHeader/Header.js +1 -1
  41. package/components/Layout/Table/Row.d.ts +1 -1
  42. package/components/Layout/index.d.ts +3 -0
  43. package/components/Layout/index.js +3 -0
  44. package/components/Loader/index.d.ts +4 -1
  45. package/components/Loader/index.js +2 -2
  46. package/components/Navigation/SlideIndicator/index.js +15 -8
  47. package/components/Navigation/Stepper/index.js +13 -13
  48. package/components/Navigation/ToggleGroup/index.d.ts +8 -1
  49. package/components/Navigation/ToggleGroup/index.js +1 -1
  50. package/components/Text/getTextStyle.d.ts +10 -17
  51. package/components/Text/getTextStyle.js +24 -31
  52. package/components/Text/index.d.ts +6 -5
  53. package/components/Text/index.js +9 -3
  54. package/components/chart/index.d.ts +0 -1
  55. package/components/chart/index.js +6 -6
  56. package/components/cta/Button/getButtonStyle.js +12 -12
  57. package/components/cta/Button/index.d.ts +5 -16
  58. package/components/cta/Button/index.js +15 -16
  59. package/components/cta/Link/getLinkStyle.js +8 -8
  60. package/components/cta/Link/index.js +2 -2
  61. package/components/cta/getCtaStyle.d.ts +2 -2
  62. package/components/drawer/Notification/index.js +6 -12
  63. package/components/index.d.ts +1 -0
  64. package/components/index.js +1 -0
  65. package/components/message/Alert/index.d.ts +0 -1
  66. package/components/message/Alert/index.js +6 -6
  67. package/components/styled.d.ts +15 -0
  68. package/components/styled.js +12 -0
  69. package/components/tags/Badge/index.d.ts +2 -2
  70. package/components/tags/Badge/index.js +10 -10
  71. package/icons/Close.js +1 -1
  72. package/package.json +8 -10
  73. package/styles/InvertTheme.d.ts +0 -1
  74. package/styles/StyleProvider.d.ts +0 -9
  75. package/styles/StyleProvider.js +1 -1
  76. package/styles/helpers.d.ts +3 -1
  77. package/styles/helpers.js +4 -7
  78. package/styles/theme.d.ts +10 -34
  79. package/styles/theme.js +19 -37
package/README.md CHANGED
@@ -1,14 +1,16 @@
1
1
  # `@ledgerhq/native-ui`
2
2
 
3
- ![build](https://github.com/LedgerHQ/ui/actions/workflows/native.yml/badge.svg)
3
+ [![build](https://github.com/LedgerHQ/ui/actions/workflows/native.yml/badge.svg)](https://github.com/LedgerHQ/ui/actions/workflows/native.yml)
4
+ [![npm](https://img.shields.io/npm/v/@ledgerhq/native-ui)](https://www.npmjs.com/package/@ledgerhq/native-ui)
5
+ [![storybook](https://img.shields.io/badge/Storybook-📚-61DBFB)](https://ledger-live-ui-native.vercel.app)
4
6
 
5
- #### Design and interface resources
7
+ ### Design and interface resources for React Native
6
8
 
7
- This package contains [React Native](https://reactnative.dev/) components and styles built on top of our design system and used internally at [Ledger](https://www.ledger.com/).
9
+ #### This package contains [React Native](https://reactnative.dev/) components and styles built on top of our design system and used internally at [Ledger](https://www.ledger.com/).
8
10
 
9
11
  ## Reference
10
12
 
11
- [📚 The storybook is hosted here.](https://ledger-live-ui-native.vercel.app/)
13
+ **[🔗 Storybook](https://ledger-live-ui-native.vercel.app/)**
12
14
 
13
15
  ## Installation
14
16
 
@@ -18,24 +20,22 @@ This package contains [React Native](https://reactnative.dev/) components and st
18
20
  npm i @ledgerhq/native-ui
19
21
  ```
20
22
 
21
- ### Required Dependencies
23
+ ### Peer dependencies
22
24
 
23
- **Skip this step if your project is using Expo! ✨**
25
+ _This library uses the following packages under the hood and relies on them being installed separately to avoid package duplication._
24
26
 
25
27
  ```sh
26
- npm i react react-native@^0.64.0 react-native-reanimated@~2.2.3 react-native-svg@^12.1.1
28
+ npm i styled-components react-native-reanimated react-native-svg
27
29
  ```
28
30
 
29
- Then, follow the installation instructions for:
31
+ ### Additional setup
30
32
 
31
- - [react-native-reanimated](https://docs.swmansion.com/react-native-reanimated/docs/2.2.0/installation)
32
- - [react-native-svg](https://github.com/react-native-svg/react-native-svg#installation)
33
+ **Skip this step if your project is managed by Expo.**
33
34
 
34
- ### Recommended Dependencies
35
+ Follow the installation instructions for:
35
36
 
36
- ```sh
37
- npm i styled-components
38
- ```
37
+ - [react-native-reanimated](https://docs.swmansion.com/react-native-reanimated/docs/2.2.0/installation)
38
+ - [react-native-svg](https://github.com/react-native-svg/react-native-svg#installation)
39
39
 
40
40
  ## Usage
41
41
 
@@ -62,7 +62,7 @@ import { Flex, Text } from "@ledgerhq/native-ui";
62
62
  function Hello() {
63
63
  return (
64
64
  <Flex flexDirection="column" alignItems="center">
65
- <Text type="h1" color="palette.neutral.c100">
65
+ <Text variant="h1" color="neutral.c100">
66
66
  Hello, world!
67
67
  </Text>
68
68
  </Flex>
@@ -133,7 +133,7 @@ import { useFonts } from "expo-font";
133
133
 
134
134
  function Logo() {
135
135
  const theme = useTheme();
136
- return <Logos.LedgerLiveRegular color={theme.colors.palette.neutral.c100} />;
136
+ return <Logos.LedgerLiveRegular color={theme.colors.neutral.c100} />;
137
137
  }
138
138
 
139
139
  function FontProvider({ children }) {
@@ -163,10 +163,10 @@ export default function App() {
163
163
  justifyContent="center"
164
164
  alignItems="center"
165
165
  flexDirection="column"
166
- backgroundColor="palette.neutral.c00"
166
+ backgroundColor="neutral.c00"
167
167
  >
168
168
  <Logo />
169
- <Text type="h2" color="palette.neutral.c100" my={10}>
169
+ <Text variant="h2" color="neutral.c100" my={10}>
170
170
  Hello, world!
171
171
  </Text>
172
172
  <Switch
@@ -190,7 +190,7 @@ import { useTheme } from "styled-components/native";
190
190
 
191
191
  function Logo() {
192
192
  const theme = useTheme();
193
- return <Logos.LedgerLiveRegular color={theme.colors.palette.neutral.c100} />;
193
+ return <Logos.LedgerLiveRegular color={theme.colors.neutral.c100} />;
194
194
  }
195
195
 
196
196
  export default function App() {
@@ -205,10 +205,10 @@ export default function App() {
205
205
  justifyContent="center"
206
206
  alignItems="center"
207
207
  flexDirection="column"
208
- backgroundColor="palette.neutral.c00"
208
+ backgroundColor="neutral.c00"
209
209
  >
210
210
  <Logo />
211
- <Text type="h2" color="palette.neutral.c100" my={10}>
211
+ <Text variant="h2" color="neutral.c100" my={10}>
212
212
  Hello, world!
213
213
  </Text>
214
214
  <Switch
@@ -0,0 +1 @@
1
+ export * from "@ledgerhq/icons-ui/native";
@@ -0,0 +1 @@
1
+ export * from "@ledgerhq/icons-ui/native";
@@ -1,4 +1,3 @@
1
- /// <reference types="react" />
2
1
  declare type Props = {
3
2
  width?: number | string;
4
3
  height?: number | string;
@@ -1,4 +1,3 @@
1
- /// <reference types="react" />
2
1
  declare type Props = {
3
2
  width?: number | string;
4
3
  height?: number | string;
@@ -0,0 +1,45 @@
1
+ /// <reference types="styled-components-react-native" />
2
+ import React from "react";
3
+ import { ScrollView, ViewProps } from "react-native";
4
+ import type { Props as FlexboxProps } from "../Layout/Flex";
5
+ declare const HorizontalScrollView: import("styled-components").StyledComponent<typeof ScrollView, import("styled-components").DefaultTheme, {
6
+ horizontal: true;
7
+ }, "horizontal">;
8
+ export declare type Props = React.PropsWithChildren<{
9
+ /**
10
+ * Forces the selection of a specific item of the carousel.
11
+ */
12
+ activeIndex?: number;
13
+ /**
14
+ * Called when the active carousel index is updated.
15
+ */
16
+ onChange?: (index: number) => void;
17
+ /**
18
+ * This number in milliseconds will enable automatic scrolling when defined.
19
+ *
20
+ * The Carousel will scroll to the next item after this delay is elapsed,
21
+ * unless the user is currently dragging the content.
22
+ *
23
+ * This delay will also reset whenever the user taps on an indicator bullet to
24
+ * manually change the carousel item displayed.
25
+ */
26
+ autoDelay?: number;
27
+ /**
28
+ * Additional props to pass to the outer container.
29
+ * This container is a Flex element.
30
+ */
31
+ containerProps?: FlexboxProps;
32
+ /**
33
+ * Additional props to pass to the ScrollView element.
34
+ * See: https://reactnative.dev/docs/scrollview
35
+ */
36
+ scrollViewProps?: React.ComponentProps<typeof HorizontalScrollView>;
37
+ /**
38
+ * Additional props to pass to the indicators container.
39
+ * This container is a Flex element.
40
+ */
41
+ slideIndicatorContainerProps?: FlexboxProps & ViewProps;
42
+ }>;
43
+ declare function Carousel({ activeIndex, autoDelay, containerProps, slideIndicatorContainerProps, scrollViewProps, onChange, children, }: Props): JSX.Element;
44
+ declare const _default: React.MemoExoticComponent<typeof Carousel>;
45
+ export default _default;
@@ -0,0 +1,76 @@
1
+ import React, { useEffect, useState, useRef, useCallback } from "react";
2
+ import { Platform, } from "react-native";
3
+ import styled from "styled-components/native";
4
+ import { Flex, SlideIndicator } from "../index";
5
+ const HorizontalScrollView = styled.ScrollView.attrs({ horizontal: true }) `
6
+ flex: 1;
7
+ `;
8
+ function Carousel({ activeIndex, autoDelay, containerProps, slideIndicatorContainerProps, scrollViewProps, onChange, children, }) {
9
+ const [init, setInit] = useState(false);
10
+ const [activeIndexState, setActiveIndexState] = useState(activeIndex);
11
+ const disableTimer = useRef(false);
12
+ const [resetTimer, setResetTimer] = useState({});
13
+ const dimensions = useRef(null);
14
+ const slidesLength = React.Children.count(children);
15
+ const scrollRef = useRef(null);
16
+ const fullWidth = 100 * slidesLength;
17
+ const itemWidth = !dimensions.current
18
+ ? 0
19
+ : dimensions.current.contentWidth / slidesLength;
20
+ const scrollToIndex = useCallback((index, animated = true) => {
21
+ if (scrollRef.current && dimensions.current) {
22
+ scrollRef.current.scrollTo({
23
+ x: itemWidth * index,
24
+ animated,
25
+ });
26
+ }
27
+ }, [itemWidth]);
28
+ useEffect(() => {
29
+ // On init scroll to the active index prop location - if specified.
30
+ if (init && activeIndex)
31
+ scrollToIndex(activeIndex, false);
32
+ // eslint-disable-next-line react-hooks/exhaustive-deps
33
+ }, [init]);
34
+ useEffect(() => {
35
+ if (scrollToIndex && typeof activeIndex === "number") {
36
+ scrollToIndex(activeIndex);
37
+ }
38
+ // eslint-disable-next-line react-hooks/exhaustive-deps
39
+ }, [activeIndex]);
40
+ const onContentSizeChange = (contentWidth, contentHeight) => {
41
+ dimensions.current = { contentWidth, contentHeight };
42
+ setInit(true);
43
+ };
44
+ const onScroll = ({ nativeEvent: { contentOffset, contentSize }, }) => {
45
+ const newIndex = Math.abs(Math.round((contentOffset.x / contentSize.width) * slidesLength));
46
+ setActiveIndexState(newIndex);
47
+ onChange && onChange(newIndex);
48
+ };
49
+ useEffect(() => {
50
+ if (!autoDelay)
51
+ return;
52
+ const interval = setInterval(() => {
53
+ if (!disableTimer.current) {
54
+ setActiveIndexState((index) => {
55
+ const newIndex = index ? (index + 1) % slidesLength : 0;
56
+ scrollToIndex(newIndex);
57
+ onChange && onChange(newIndex);
58
+ return newIndex;
59
+ });
60
+ }
61
+ }, autoDelay);
62
+ return () => clearInterval(interval);
63
+ }, [resetTimer, slidesLength, scrollToIndex, onChange, autoDelay]);
64
+ return (React.createElement(Flex, Object.assign({ flex: 1, width: "100%", alignItems: "center", justifyContent: "center" }, containerProps),
65
+ React.createElement(HorizontalScrollView, Object.assign({ ref: scrollRef, onScroll: onScroll, onContentSizeChange: onContentSizeChange, onScrollBeginDrag: () => {
66
+ disableTimer.current = true;
67
+ }, onScrollEndDrag: () => {
68
+ disableTimer.current = false;
69
+ }, pagingEnabled: Platform.OS !== "web", showsHorizontalScrollIndicator: false, scrollEventThrottle: 200, contentContainerStyle: { width: `${fullWidth}%` }, decelerationRate: "fast" }, scrollViewProps), React.Children.map(children, (child, index) => (React.createElement(Flex, { key: index, flex: 1 }, child)))),
70
+ React.createElement(Flex, Object.assign({ my: 8 }, slideIndicatorContainerProps),
71
+ React.createElement(SlideIndicator, { activeIndex: activeIndexState || 0, onChange: (index) => {
72
+ scrollToIndex(index);
73
+ setResetTimer({});
74
+ }, slidesLength: slidesLength }))));
75
+ }
76
+ export default React.memo(Carousel);
@@ -1,9 +1,9 @@
1
- /// <reference types="react" />
1
+ import type { BaseTextProps } from "../../Text";
2
2
  declare type CheckboxProps = {
3
3
  checked: boolean;
4
4
  onChange?: () => void;
5
5
  disabled?: boolean;
6
- label?: string;
6
+ label?: BaseTextProps["children"];
7
7
  };
8
8
  declare const Checkbox: ({ checked, onChange, disabled, label, }: CheckboxProps) => JSX.Element;
9
9
  export default Checkbox;
@@ -11,16 +11,16 @@ const Square = styled(Flex).attrs({
11
11
  width: 18px;
12
12
  height: 18px;
13
13
  border-radius: 4px;
14
- color: ${({ theme }) => theme.colors.palette.neutral.c00};
14
+ color: ${({ theme }) => theme.colors.neutral.c00};
15
15
  ${({ checked, theme }) => checked
16
- ? `background-color: ${theme.colors.palette.primary.c90};`
17
- : `border: 1px solid ${theme.colors.palette.neutral.c50};`}
16
+ ? `background-color: ${theme.colors.primary.c90};`
17
+ : `border: 1px solid ${theme.colors.neutral.c50};`}
18
18
  `;
19
19
  const Checkbox = ({ checked, onChange, disabled, label, }) => {
20
20
  const { colors, space } = useTheme();
21
21
  return (React.createElement(Pressable, { onPress: onChange, disabled: disabled },
22
22
  React.createElement(Flex, { flexDirection: "row", alignItems: "center" },
23
- React.createElement(Square, { checked: checked }, checked ? (React.createElement(CheckAlone, { size: 13, color: colors.palette.neutral.c00 })) : null),
24
- label ? (React.createElement(Text, { type: "body", color: checked ? colors.palette.primary.c90 : colors.palette.neutral.c100, style: { marginLeft: space[2] } }, label)) : null)));
23
+ React.createElement(Square, { checked: checked }, checked ? React.createElement(CheckAlone, { size: 13, color: colors.neutral.c00 }) : null),
24
+ label ? (React.createElement(Text, { variant: "body", color: checked ? colors.primary.c90 : colors.neutral.c100, style: { marginLeft: space[2] } }, label)) : null)));
25
25
  };
26
26
  export default Checkbox;
@@ -1,23 +1,119 @@
1
1
  /// <reference types="styled-components-react-native" />
2
2
  import React from "react";
3
- import { View, TextInputProps } from "react-native";
4
- declare type CommonProps = TextInputProps & {
3
+ import { TextInput, TextInputProps, StyleProp, ViewStyle } from "react-native";
4
+ export declare type CommonProps = TextInputProps & {
5
5
  disabled?: boolean;
6
6
  error?: string;
7
7
  };
8
- export declare type InputProps = CommonProps & {
9
- renderLeft?: ((props: CommonProps) => React.ReactNode) | React.ReactNode;
10
- renderRight?: ((props: CommonProps) => React.ReactNode) | React.ReactNode;
8
+ export declare type InputProps<T = string> = Omit<CommonProps, "value" | "onChange"> & {
9
+ /**
10
+ * The value of the input.
11
+ */
12
+ value: T;
13
+ /**
14
+ * A function that will render some content on the left side of the input.
15
+ */
16
+ renderLeft?: ((props: InputProps<T>) => React.ReactNode) | React.ReactNode;
17
+ /**
18
+ * A function that will render some content on the right side of the input.
19
+ */
20
+ renderRight?: ((props: InputProps<T>) => React.ReactNode) | React.ReactNode;
21
+ /**
22
+ * Triggered when the input value is updated.
23
+ */
24
+ onChange?: (value: T) => void;
25
+ /**
26
+ * Same as onChange but preserves the native event passed as the callback argument.
27
+ */
28
+ onChangeEvent?: TextInputProps["onChange"];
29
+ /**
30
+ * A function can be provided to serialize a value of any type to a string.
31
+ *
32
+ * This can be useful to wrap the `<BaseInput />` component (which expects a string)
33
+ * and create higher-level components that will automatically perform the input/output
34
+ * conversion to other types.
35
+ *
36
+ * *A serializer function should always be used in conjunction with a deserializer function.*
37
+ */
38
+ serialize?: (value: T) => string;
39
+ /**
40
+ * A deserializer can be provided to convert the html input value from a string to any other type.
41
+ *
42
+ * *A deserializer function should always be used in conjunction with a serializer function.*
43
+ */
44
+ deserialize?: (value: string) => T;
45
+ /**
46
+ * Additional style for the container element.
47
+ */
48
+ containerStyle?: StyleProp<ViewStyle>;
11
49
  };
12
- export declare const InputRenderLeftContainer: import("styled-components").StyledComponent<typeof View, import("styled-components").DefaultTheme, import("../../../Layout/Flex").Props & {
50
+ export declare const InputRenderLeftContainer: 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>> & {
51
+ columnGap?: string | number | undefined;
52
+ rowGap?: string | number | undefined;
53
+ color?: string | undefined;
54
+ display?: string | undefined;
55
+ position?: string | undefined;
56
+ maxHeight?: number | undefined;
57
+ } & {
13
58
  alignItems: string;
14
59
  flexDirection: string;
15
60
  pl: string;
16
61
  }, "pl" | "alignItems" | "flexDirection">;
17
- export declare const InputRenderRightContainer: import("styled-components").StyledComponent<typeof View, import("styled-components").DefaultTheme, import("../../../Layout/Flex").Props & {
62
+ export declare const InputRenderRightContainer: 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>> & {
63
+ columnGap?: string | number | undefined;
64
+ rowGap?: string | number | undefined;
65
+ color?: string | undefined;
66
+ display?: string | undefined;
67
+ position?: string | undefined;
68
+ maxHeight?: number | undefined;
69
+ } & {
18
70
  alignItems: string;
19
71
  flexDirection: string;
20
72
  pr: string;
21
73
  }, "pr" | "alignItems" | "flexDirection">;
22
- export default function Input(props: InputProps): JSX.Element;
23
- export {};
74
+ declare function Input<T = string>(props: InputProps<T>, ref?: React.ForwardedRef<TextInput>): JSX.Element;
75
+ declare const _default: <T>(props: Omit<CommonProps, "onChange" | "value"> & {
76
+ /**
77
+ * The value of the input.
78
+ */
79
+ value: T;
80
+ /**
81
+ * A function that will render some content on the left side of the input.
82
+ */
83
+ renderLeft?: React.ReactNode | ((props: InputProps<T>) => React.ReactNode);
84
+ /**
85
+ * A function that will render some content on the right side of the input.
86
+ */
87
+ renderRight?: React.ReactNode | ((props: InputProps<T>) => React.ReactNode);
88
+ /**
89
+ * Triggered when the input value is updated.
90
+ */
91
+ onChange?: ((value: T) => void) | undefined;
92
+ /**
93
+ * Same as onChange but preserves the native event passed as the callback argument.
94
+ */
95
+ onChangeEvent?: ((e: import("react-native").NativeSyntheticEvent<import("react-native").TextInputChangeEventData>) => void) | undefined;
96
+ /**
97
+ * A function can be provided to serialize a value of any type to a string.
98
+ *
99
+ * This can be useful to wrap the `<BaseInput />` component (which expects a string)
100
+ * and create higher-level components that will automatically perform the input/output
101
+ * conversion to other types.
102
+ *
103
+ * *A serializer function should always be used in conjunction with a deserializer function.*
104
+ */
105
+ serialize?: ((value: T) => string) | undefined;
106
+ /**
107
+ * A deserializer can be provided to convert the html input value from a string to any other type.
108
+ *
109
+ * *A deserializer function should always be used in conjunction with a serializer function.*
110
+ */
111
+ deserialize?: ((value: string) => T) | undefined;
112
+ /**
113
+ * Additional style for the container element.
114
+ */
115
+ containerStyle?: StyleProp<ViewStyle>;
116
+ } & {
117
+ ref?: React.ForwardedRef<TextInput> | undefined;
118
+ }) => ReturnType<typeof Input>;
119
+ export default _default;
@@ -9,8 +9,7 @@ var __rest = (this && this.__rest) || function (s, e) {
9
9
  }
10
10
  return t;
11
11
  };
12
- import React from "react";
13
- import { View } from "react-native";
12
+ import React, { useMemo, useCallback } from "react";
14
13
  import styled, { css } from "styled-components/native";
15
14
  import Text from "../../../Text";
16
15
  import FlexBox from "../../../Layout/Flex";
@@ -18,38 +17,38 @@ const InputContainer = styled.View `
18
17
  display: flex;
19
18
  flex-direction: row;
20
19
  width: 100%;
21
- background: ${(p) => p.theme.colors.palette.neutral.c00};
20
+ background: ${(p) => p.theme.colors.neutral.c00};
22
21
  height: 48px;
23
- border: ${(p) => `1px solid ${p.theme.colors.palette.neutral.c40}`};
22
+ border: ${(p) => `1px solid ${p.theme.colors.neutral.c40}`};
24
23
  border-radius: 24px;
25
- color: ${(p) => p.theme.colors.palette.neutral.c100};
24
+ color: ${(p) => p.theme.colors.neutral.c100};
26
25
 
27
26
  ${(p) => p.disabled &&
28
27
  css `
29
- color: ${p.theme.colors.palette.neutral.c60};
30
- background: ${(p) => p.theme.colors.palette.neutral.c30};
28
+ color: ${p.theme.colors.neutral.c60};
29
+ background: ${(p) => p.theme.colors.neutral.c30};
31
30
  `};
32
31
 
33
32
  ${(p) => p.focus &&
34
33
  !p.error &&
35
34
  css `
36
- border: 1px solid ${p.theme.colors.palette.primary.c80};
35
+ border: 1px solid ${p.theme.colors.primary.c80};
37
36
  `};
38
37
 
39
38
  ${(p) => p.error &&
40
39
  !p.disabled &&
41
40
  css `
42
- border: 1px solid ${p.theme.colors.palette.error.c100};
41
+ border: 1px solid ${p.theme.colors.error.c100};
43
42
  `};
44
43
 
45
44
  ${(p) => p.disabled &&
46
45
  css `
47
- color: ${p.theme.colors.palette.neutral.c60};
48
- background: ${(p) => p.theme.colors.palette.neutral.c30};
46
+ color: ${p.theme.colors.neutral.c60};
47
+ background: ${(p) => p.theme.colors.neutral.c30};
49
48
  `};
50
49
  `;
51
50
  const BaseInput = styled.TextInput.attrs((p) => ({
52
- selectionColor: p.theme.colors.palette.primary.c80,
51
+ selectionColor: p.theme.colors.primary.c80,
53
52
  })) `
54
53
  height: 100%;
55
54
  width: 100%;
@@ -61,7 +60,7 @@ const BaseInput = styled.TextInput.attrs((p) => ({
61
60
  padding-right: 20px;
62
61
  `;
63
62
  const InputErrorContainer = styled(Text) `
64
- color: ${(p) => p.theme.colors.palette.error.c100};
63
+ color: ${(p) => p.theme.colors.error.c100};
65
64
  margin-left: 12px;
66
65
  `;
67
66
  export const InputRenderLeftContainer = styled(FlexBox).attrs(() => ({
@@ -74,13 +73,22 @@ export const InputRenderRightContainer = styled(FlexBox).attrs(() => ({
74
73
  flexDirection: "row",
75
74
  pr: "16px",
76
75
  })) ``;
77
- export default function Input(props) {
78
- const { value, disabled, error, renderLeft, renderRight } = props, textInputProps = __rest(props, ["value", "disabled", "error", "renderLeft", "renderRight"]);
76
+ // Yes, this is dirty. If you can figure out a better way please change the code :).
77
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
78
+ const IDENTITY = (_) => _;
79
+ function Input(props, ref) {
80
+ const { value, onChange, onChangeText, onChangeEvent, disabled, error, renderLeft, renderRight, serialize = IDENTITY, deserialize = IDENTITY, containerStyle } = props, textInputProps = __rest(props, ["value", "onChange", "onChangeText", "onChangeEvent", "disabled", "error", "renderLeft", "renderRight", "serialize", "deserialize", "containerStyle"]);
81
+ const inputValue = useMemo(() => serialize(value), [serialize, value]);
82
+ const handleChange = useCallback((value) => {
83
+ onChange && onChange(deserialize(value));
84
+ onChangeText && onChangeText(value);
85
+ }, [onChange, onChangeText, deserialize]);
79
86
  const [focus, setFocus] = React.useState(false);
80
- return (React.createElement(View, { style: { display: "flex", width: "100%" } },
87
+ return (React.createElement(FlexBox, { width: "100%", style: containerStyle !== null && containerStyle !== void 0 ? containerStyle : undefined },
81
88
  React.createElement(InputContainer, { disabled: disabled, focus: focus, error: error },
82
89
  typeof renderLeft === "function" ? renderLeft(props) : renderLeft,
83
- React.createElement(BaseInput, Object.assign({}, textInputProps, { editable: !disabled, disabled: disabled, error: error, value: value, onFocus: () => setFocus(true), onBlur: () => setFocus(false) })),
90
+ React.createElement(BaseInput, Object.assign({ ref: ref }, textInputProps, { value: inputValue, onChange: onChangeEvent, onChangeText: handleChange, editable: !disabled, disabled: disabled, error: error, onFocus: () => setFocus(true), onBlur: () => setFocus(false) })),
84
91
  typeof renderRight === "function" ? renderRight(props) : renderRight),
85
92
  !!error && !disabled && (React.createElement(InputErrorContainer, null, error))));
86
93
  }
94
+ export default React.forwardRef(Input);
@@ -1,5 +1,16 @@
1
- /// <reference types="react" />
1
+ import React from "react";
2
+ import { TextInput } from "react-native";
2
3
  import { InputProps } from "../BaseInput";
3
- export default function LegendInput({ legend, ...inputProps }: InputProps & {
4
+ declare const _default: React.ForwardRefExoticComponent<Omit<import("../BaseInput").CommonProps, "onChange" | "value"> & {
5
+ value: string;
6
+ renderLeft?: React.ReactNode | ((props: InputProps<string>) => React.ReactNode);
7
+ renderRight?: React.ReactNode | ((props: InputProps<string>) => React.ReactNode);
8
+ onChange?: ((value: string) => void) | undefined;
9
+ onChangeEvent?: ((e: import("react-native").NativeSyntheticEvent<import("react-native").TextInputChangeEventData>) => void) | undefined;
10
+ serialize?: ((value: string) => string) | undefined;
11
+ deserialize?: ((value: string) => string) | undefined;
12
+ containerStyle?: import("react-native").StyleProp<import("react-native").ViewStyle>;
13
+ } & {
4
14
  legend: string;
5
- }): JSX.Element;
15
+ } & React.RefAttributes<TextInput>>;
16
+ export default _default;
@@ -12,8 +12,9 @@ var __rest = (this && this.__rest) || function (s, e) {
12
12
  import React from "react";
13
13
  import Input, { InputRenderRightContainer } from "../BaseInput";
14
14
  import Text from "../../../Text";
15
- export default function LegendInput(_a) {
15
+ function LegendInput(_a, ref) {
16
16
  var { legend } = _a, inputProps = __rest(_a, ["legend"]);
17
- return (React.createElement(Input, Object.assign({}, inputProps, { renderRight: React.createElement(InputRenderRightContainer, null,
18
- React.createElement(Text, { color: "palette.neutral.c70", type: "body" }, legend)) })));
17
+ return (React.createElement(Input, Object.assign({ ref: ref }, inputProps, { renderRight: React.createElement(InputRenderRightContainer, null,
18
+ React.createElement(Text, { color: "neutral.c70", variant: "body" }, legend)) })));
19
19
  }
20
+ export default React.forwardRef(LegendInput);
@@ -1,6 +1,18 @@
1
- /// <reference types="react" />
1
+ import React from "react";
2
+ import { TextInput } from "react-native";
2
3
  import { InputProps } from "../BaseInput";
3
- export default function NumberInput({ onPercentClick, max, value, disabled, ...inputProps }: InputProps & {
4
+ declare const _default: React.ForwardRefExoticComponent<Omit<import("../BaseInput").CommonProps, "onChange" | "value"> & {
5
+ value: number | undefined;
6
+ renderLeft?: React.ReactNode | ((props: InputProps<number | undefined>) => React.ReactNode);
7
+ renderRight?: React.ReactNode | ((props: InputProps<number | undefined>) => React.ReactNode);
8
+ onChange?: ((value: number | undefined) => void) | undefined;
9
+ onChangeEvent?: ((e: import("react-native").NativeSyntheticEvent<import("react-native").TextInputChangeEventData>) => void) | undefined;
10
+ serialize?: ((value: number | undefined) => string) | undefined;
11
+ deserialize?: ((value: string) => number | undefined) | undefined;
12
+ containerStyle?: import("react-native").StyleProp<import("react-native").ViewStyle>;
13
+ } & {
4
14
  onPercentClick: (percent: number) => void;
5
- max: number;
6
- }): JSX.Element;
15
+ min?: number | undefined;
16
+ max?: number | undefined;
17
+ } & React.RefAttributes<TextInput>>;
18
+ export default _default;
@@ -16,12 +16,8 @@ import Input from "../BaseInput";
16
16
  import FlexBox from "../../../Layout/Flex";
17
17
  import Text from "../../../Text";
18
18
  const PercentButton = styled(TouchableOpacity) `
19
- color: ${(p) => p.active
20
- ? p.theme.colors.palette.neutral.c00
21
- : p.theme.colors.palette.neutral.c70};
22
- background-color: ${(p) => p.active
23
- ? p.theme.colors.palette.neutral.c100
24
- : p.theme.colors.palette.neutral.c00};
19
+ color: ${(p) => p.active ? p.theme.colors.neutral.c00 : p.theme.colors.neutral.c70};
20
+ background-color: ${(p) => p.active ? p.theme.colors.neutral.c100 : p.theme.colors.neutral.c00};
25
21
  border-radius: 100px;
26
22
  border-width: 0;
27
23
  height: 31px;
@@ -31,13 +27,25 @@ const PercentButton = styled(TouchableOpacity) `
31
27
  justify-content: center;
32
28
  align-items: center;
33
29
  `;
34
- export default function NumberInput(_a) {
30
+ function serialize(value) {
31
+ return value ? "" + value : "";
32
+ }
33
+ function deserialize(value) {
34
+ try {
35
+ return parseFloat(value);
36
+ }
37
+ catch (error) {
38
+ return undefined;
39
+ }
40
+ }
41
+ function NumberInput(_a, ref) {
35
42
  var { onPercentClick, max, value, disabled } = _a, inputProps = __rest(_a, ["onPercentClick", "max", "value", "disabled"]);
36
- return (React.createElement(Input, Object.assign({}, inputProps, { value: value, disabled: disabled, keyboardType: "numeric", renderRight: React.createElement(FlexBox, { alignItems: "center", justifyContent: "center", py: "3px", mr: "8px", flexDirection: "row" }, [0.25, 0.5, 0.75, 1].map((percent) => {
43
+ return (React.createElement(Input, Object.assign({ ref: ref, serialize: serialize, deserialize: deserialize }, inputProps, { value: value, disabled: disabled, keyboardType: "numeric", renderRight: React.createElement(FlexBox, { alignItems: "center", justifyContent: "center", py: "3px", mr: "8px", flexDirection: "row" }, [0.25, 0.5, 0.75, 1].map((percent) => {
37
44
  const active = !!value && !!max && Number(value) === percent * Number(max);
38
45
  return (React.createElement(PercentButton, { key: percent, onPress: () => onPercentClick(percent), active: active, disabled: disabled },
39
- React.createElement(Text, { type: "small", color: active ? "palette.neutral.c00" : "palette.neutral.c70" },
46
+ React.createElement(Text, { variant: "small", color: active ? "neutral.c00" : "neutral.c70" },
40
47
  percent * 100,
41
48
  "%")));
42
49
  })) })));
43
50
  }
51
+ export default React.forwardRef(NumberInput);
@@ -1,6 +1,17 @@
1
- /// <reference types="react" />
1
+ import React from "react";
2
+ import { TextInput } from "react-native";
2
3
  import { GestureResponderEvent } from "react-native";
3
4
  import { InputProps } from "../BaseInput";
4
- export default function QrCodeInput({ onQrCodeClick, ...inputProps }: InputProps & {
5
- onQrCodeClick?: (event: GestureResponderEvent) => void;
6
- }): JSX.Element;
5
+ declare const _default: React.ForwardRefExoticComponent<Omit<import("../BaseInput").CommonProps, "onChange" | "value"> & {
6
+ value: string;
7
+ renderLeft?: React.ReactNode | ((props: InputProps<string>) => React.ReactNode);
8
+ renderRight?: React.ReactNode | ((props: InputProps<string>) => React.ReactNode);
9
+ onChange?: ((value: string) => void) | undefined;
10
+ onChangeEvent?: ((e: import("react-native").NativeSyntheticEvent<import("react-native").TextInputChangeEventData>) => void) | undefined;
11
+ serialize?: ((value: string) => string) | undefined;
12
+ deserialize?: ((value: string) => string) | undefined;
13
+ containerStyle?: import("react-native").StyleProp<import("react-native").ViewStyle>;
14
+ } & {
15
+ onQrCodeClick?: ((event: GestureResponderEvent) => void) | undefined;
16
+ } & React.RefAttributes<TextInput>>;
17
+ export default _default;