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