on 07f7167 help sign in
bridge/src/components/Inputs.js
252 lines 6.0 kB history raw
1import React, { useCallback, useState, useMemo } from 'react';
2import { AccessoryIcon, useForm } from 'indigo-react';
3import { identity } from 'lodash';
4import * as bip39 from 'bip39';
6import InputSigil from 'components/InputSigil';
8import { DEFAULT_HD_PATH } from 'lib/wallet';
9import {
10 validateNotEmpty,
11 validateMnemonic,
12 validatePoint,
13 validateTicket,
14 validateEmail,
15 validateLength,
16 validateHexString,
17 validateOneOf,
18 validateMaximumPatpByteLength,
19 validatePatpByteLength,
20} from 'lib/validators';
21import { prependSig } from 'lib/transformers';
23const EXAMPLE_PRIVATE_KEY =
24 '0xa44de2416ee6beb2f323fab48b432925c9785808d33a6ca6d7ba00b45e9370c3';
26// const RequiredInput = advancedInput({
27// WrappedComponent: Input,
28// validators: [validateNotEmpty],
29// });
31// const NetworkKeyInput = advancedInput({
32// WrappedComponent: Input,
33// validators: [validateNotEmpty, validateNetworkKey],
34// });
36// const NetworkSeedInput = advancedInput({
37// WrappedComponent: Input,
38// validators: [validateNotEmpty, validateNetworkSeed],
39// });
41// const AddressInput = advancedInput({
42// WrappedComponent: Input,
43// validators: [validateEthereumAddress, validateNotEmpty],
44// });
46// const GalaxyInput = advancedInput({
47// WrappedComponent: Input,
48// validators: [validateGalaxy, validateNotEmpty],
49// transformers: [prependSig],
50// });
52// pulls out the first input from a useForm() call
53function useFirstOf({ inputs, setValue, ...rest }, mapper = identity) {
54 // ask the mapper function for any values to overwrite
55 const input = {
56 ...inputs[0],
57 ...mapper(inputs[0]),
58 };
59 // memoize the setValue callback for manually setting the value
60 // in response to some imperative event
61 const _setValue = useCallback(value => setValue(input.name, value), [
62 setValue,
63 input.name,
64 ]);
66 // provide the first input as the first element
67 // _and_ as the second element to facilitate destructuring
68 // and then provide the pass/error/setValue/etc properties at the end
69 return [
70 input,
71 input,
72 {
73 ...rest,
74 setValue: _setValue,
75 },
76 ];
79export function usePassphraseInput(props) {
80 return useFirstOf(
81 useForm([
82 {
83 type: 'password',
84 autoComplete: 'off',
85 placeholder: 'Passphrase',
86 ...props,
87 },
88 ])
89 );
92export function useHexInput({ length, ...rest }) {
93 return useFirstOf(
94 useForm([
95 {
96 type: 'text', // or password
97 autoComplete: 'off',
98 placeholder: EXAMPLE_PRIVATE_KEY,
99 validators: useMemo(
100 () => [
101 validateHexString,
102 validateLength(length + 2),
103 validateNotEmpty,
104 ],
105 [length]
106 ),
107 ...rest,
108 },
109 ])
110 );
113const kExampleMnemonic = bip39.generateMnemonic();
114const kMnemonicValidators = [validateMnemonic, validateNotEmpty];
115export function useMnemonicInput(props) {
116 return useFirstOf(
117 useForm([
118 {
119 type: 'text',
120 autoComplete: 'off',
121 placeholder: `e.g. ${kExampleMnemonic}`,
122 validators: kMnemonicValidators,
123 ...props,
124 },
125 ])
126 );
129export function useHdPathInput(props) {
130 return useFirstOf(
131 useForm([
132 {
133 type: 'text',
134 autoComplete: 'off',
135 placeholder: `e.g. ${DEFAULT_HD_PATH}`,
136 ...props,
137 },
138 ])
139 );
142const kTicketValidators = [
143 validateTicket,
144 validatePatpByteLength(8), // tickets are 8 bytes of patp
145 validateNotEmpty,
146];
147//TODO needs to be fancier, displaying sig and dashes instead of •ing all
148const kTicketTransformers = [prependSig];
149export function useTicketInput({ validators = [], deriving = false, ...rest }) {
150 return useFirstOf(
151 useForm([
152 {
153 type: 'password',
154 label: 'Ticket',
155 placeholder: 'e.g. ~ragtyd-modwen-bostec-hinsep',
156 validators: useMemo(() => [...validators, ...kTicketValidators], [
157 validators,
158 ]),
159 transformers: kTicketTransformers,
160 mono: true,
161 ...rest,
162 },
163 ]),
164 ({ error, pass }) => ({
165 accessory: error ? (
166 <AccessoryIcon.Failure />
167 ) : deriving ? (
168 <AccessoryIcon.Pending />
169 ) : pass ? (
170 <AccessoryIcon.Success />
171 ) : null,
172 })
173 );
176const kPointValidators = [
177 validatePoint,
178 validateMaximumPatpByteLength(4),
179 validateNotEmpty,
180];
181const kPointTransformers = [prependSig];
182export function usePointInput(rest) {
183 const [lastValidPoint, setLastValidPoint] = useState('');
184 return useFirstOf(
185 useForm([
186 {
187 type: 'text',
188 label: 'Point',
189 placeholder: 'e.g. ~zod',
190 validators: kPointValidators,
191 transformers: kPointTransformers,
192 mono: true,
193 onValue: setLastValidPoint,
194 ...rest,
195 },
196 ]),
197 ({ error, pass, focused }) => ({
198 accessory: lastValidPoint ? (
199 <InputSigil
200 patp={lastValidPoint}
201 size={44}
202 margin={8}
203 pass={pass}
204 focused={focused}
205 error={error}
206 />
207 ) : null,
208 })
209 );
212export function useCheckboxInput({ initialValue, ...rest }) {
213 return useFirstOf(
214 useForm([
215 {
216 type: 'checkbox',
217 ...rest,
218 },
219 ])
220 );
223export function useSelectInput({ initialValue, options, ...rest }) {
224 return useFirstOf(
225 useForm([
226 {
227 type: 'select',
228 validators: useMemo(
229 () => [
230 validateOneOf(
231 options.map(option => option.value),
232 validateNotEmpty
233 ),
234 ],
235 [options]
236 ),
237 options,
238 initialValue: initialValue || options[0].value,
239 ...rest,
240 },
241 ])
242 );
245const kEmailValidators = [validateEmail, validateNotEmpty];
246export const buildEmailInputConfig = extra => ({
247 type: 'email',
248 autoComplete: 'off',
249 validators: kEmailValidators,
250 initialValue: '',
251 ...extra,
252});