on 926eace help sign in
bridge/src/components/Inputs.js
248 lines 5.9 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 = [validateTicket, validateNotEmpty];
143//TODO needs to be fancier, displaying sig and dashes instead of •ing all
144const kTicketTransformers = [prependSig];
145export function useTicketInput({ validators = [], deriving = false, ...rest }) {
146 return useFirstOf(
147 useForm([
148 {
149 type: 'password',
150 label: 'Ticket',
151 placeholder: 'e.g. ~ragtyd-modwen-bostec-hinsep',
152 validators: useMemo(() => [...validators, ...kTicketValidators], [
153 validators,
154 ]),
155 transformers: kTicketTransformers,
156 mono: true,
157 ...rest,
158 },
159 ]),
160 ({ error, pass }) => ({
161 accessory: error ? (
162 <AccessoryIcon.Failure />
163 ) : deriving ? (
164 <AccessoryIcon.Pending />
165 ) : pass ? (
166 <AccessoryIcon.Success />
167 ) : null,
168 })
169 );
172const kPointValidators = [
173 validatePoint,
174 validateMaximumPatpByteLength(4),
175 validateNotEmpty,
176];
177const kPointTransformers = [prependSig];
178export function usePointInput(rest) {
179 const [lastValidPoint, setLastValidPoint] = useState('');
180 return useFirstOf(
181 useForm([
182 {
183 type: 'text',
184 label: 'Point',
185 placeholder: 'e.g. ~zod',
186 validators: kPointValidators,
187 transformers: kPointTransformers,
188 mono: true,
189 onValue: setLastValidPoint,
190 ...rest,
191 },
192 ]),
193 ({ error, pass, focused }) => ({
194 accessory: lastValidPoint ? (
195 <InputSigil
196 patp={lastValidPoint}
197 size={44}
198 margin={8}
199 pass={pass}
200 focused={focused}
201 error={error}
202 />
203 ) : null,
204 })
205 );
208export function useCheckboxInput({ initialValue, ...rest }) {
209 return useFirstOf(
210 useForm([
211 {
212 type: 'checkbox',
213 ...rest,
214 },
215 ])
216 );
219export function useSelectInput({ initialValue, options, ...rest }) {
220 return useFirstOf(
221 useForm([
222 {
223 type: 'select',
224 validators: useMemo(
225 () => [
226 validateOneOf(
227 options.map(option => option.value),
228 validateNotEmpty
229 ),
230 ],
231 [options]
232 ),
233 options,
234 initialValue: initialValue || options[0].value,
235 ...rest,
236 },
237 ])
238 );
241const kEmailValidators = [validateEmail, validateNotEmpty];
242export const buildEmailInputConfig = extra => ({
243 type: 'email',
244 autoComplete: 'off',
245 validators: kEmailValidators,
246 initialValue: '',
247 ...extra,
248});