on dee2cd5 help sign in
bridge/src/lib/useInputs.js
239 lines 5.6 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 { DEFAULT_HD_PATH } from 'lib/wallet';
7import {
8 validateNotEmpty,
9 validateMnemonic,
10 validatePoint,
11 validateTicket,
12 validateEmail,
13 validateLength,
14 validateHexString,
15 validateOneOf,
16 validateMaximumPatpByteLength,
17 validateEthereumAddress,
18} from 'lib/validators';
19import { prependSig } from 'lib/transformers';
21import InputSigil from 'components/InputSigil';
23const EXAMPLE_PRIVATE_KEY =
24 '0xa44de2416ee6beb2f323fab48b432925c9785808d33a6ca6d7ba00b45e9370c3';
26// pulls out the first input from a useForm() call
27function useFirstOf({ inputs, setValue, ...rest }, mapper = identity) {
28 // ask the mapper function for any values to overwrite
29 const input = {
30 ...inputs[0],
31 ...mapper(inputs[0]),
32 };
33 // memoize the setValue callback for manually setting the value
34 // in response to some imperative event
35 const _setValue = useCallback(value => setValue(input.name, value), [
36 setValue,
37 input.name,
38 ]);
40 // provide the first input as the first element
41 // _and_ as the second element to facilitate destructuring
42 // and then provide the pass/error/setValue/etc properties at the end
43 return [
44 input,
45 input,
46 {
47 ...rest,
48 setValue: _setValue,
49 },
50 ];
53export function usePassphraseInput(props) {
54 return useFirstOf(
55 useForm([
56 {
57 type: 'password',
58 autoComplete: 'off',
59 placeholder: 'Passphrase',
60 ...props,
61 },
62 ])
63 );
66export function useHexInput({ length, ...rest }) {
67 return useFirstOf(
68 useForm([
69 {
70 type: 'text', // or password
71 autoComplete: 'off',
72 placeholder: EXAMPLE_PRIVATE_KEY,
73 validators: useMemo(
74 () => [
75 validateHexString,
76 validateLength(length + 2),
77 validateNotEmpty,
78 ],
79 [length]
80 ),
81 ...rest,
82 },
83 ])
84 );
87const kExampleMnemonic = bip39.generateMnemonic();
88const kMnemonicValidators = [validateMnemonic, validateNotEmpty];
89export function useMnemonicInput(props) {
90 return useFirstOf(
91 useForm([
92 {
93 type: 'text',
94 autoComplete: 'off',
95 placeholder: `e.g. ${kExampleMnemonic}`,
96 validators: kMnemonicValidators,
97 ...props,
98 },
99 ])
100 );
103export function useHdPathInput(props) {
104 return useFirstOf(
105 useForm([
106 {
107 type: 'text',
108 autoComplete: 'off',
109 placeholder: `e.g. ${DEFAULT_HD_PATH}`,
110 ...props,
111 },
112 ])
113 );
116const kTicketValidators = [validateTicket, validateNotEmpty];
117//TODO needs to be fancier, displaying sig and dashes instead of •ing all
118const kTicketTransformers = [prependSig];
119export function useTicketInput({ validators = [], deriving = false, ...rest }) {
120 return useFirstOf(
121 useForm([
122 {
123 type: 'password',
124 label: 'Ticket',
125 placeholder: 'e.g. ~ragtyd-modwen-bostec-hinsep',
126 validators: useMemo(() => [...validators, ...kTicketValidators], [
127 validators,
128 ]),
129 transformers: kTicketTransformers,
130 mono: true,
131 ...rest,
132 },
133 ]),
134 ({ error, pass }) => ({
135 accessory: error ? (
136 <AccessoryIcon.Failure />
137 ) : deriving ? (
138 <AccessoryIcon.Pending />
139 ) : pass ? (
140 <AccessoryIcon.Success />
141 ) : null,
142 })
143 );
146const kPointValidators = [
147 validatePoint,
148 validateMaximumPatpByteLength(4),
149 validateNotEmpty,
150];
151const kPointTransformers = [prependSig];
152export function usePointInput(rest) {
153 const [lastValidPoint, setLastValidPoint] = useState('');
154 return useFirstOf(
155 useForm([
156 {
157 type: 'text',
158 label: 'Point',
159 placeholder: 'e.g. ~zod',
160 validators: kPointValidators,
161 transformers: kPointTransformers,
162 mono: true,
163 onValue: setLastValidPoint,
164 ...rest,
165 },
166 ]),
167 ({ error, pass, focused }) => ({
168 accessory: lastValidPoint ? (
169 <InputSigil
170 patp={lastValidPoint}
171 size={44}
172 margin={8}
173 pass={pass}
174 focused={focused}
175 error={error}
176 />
177 ) : null,
178 })
179 );
182export function useCheckboxInput({ initialValue, ...rest }) {
183 return useFirstOf(
184 useForm([
185 {
186 type: 'checkbox',
187 ...rest,
188 },
189 ])
190 );
193export function useSelectInput({ initialValue, options, ...rest }) {
194 return useFirstOf(
195 useForm([
196 {
197 type: 'select',
198 validators: useMemo(
199 () => [
200 validateOneOf(
201 options.map(option => option.value),
202 validateNotEmpty
203 ),
204 ],
205 [options]
206 ),
207 options,
208 initialValue: initialValue || options[0].value,
209 ...rest,
210 },
211 ])
212 );
215const kAddressValidators = [validateEthereumAddress, validateNotEmpty];
216export function useAddressInput({ ...rest }) {
217 return useFirstOf(
218 useForm([
219 {
220 type: 'string',
221 label: 'Ethereum Address',
222 placeholder: 'e.g. 0x6DEfFb0caFDB11D175F123F6891AA64F01c24F7d',
223 autoComplete: 'off',
224 validators: kAddressValidators,
225 mono: true,
226 ...rest,
227 },
228 ])
229 );
232const kEmailValidators = [validateEmail, validateNotEmpty];
233export const buildEmailInputConfig = extra => ({
234 type: 'email',
235 autoComplete: 'off',
236 validators: kEmailValidators,
237 initialValue: '',
238 ...extra,
239});