Rework inputs (#26)
This commit is contained in:
@@ -5,6 +5,7 @@
|
||||
import { OnActionFromCtx } from '../../components/types';
|
||||
|
||||
import React, { useState } from 'react';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import { ActionBar, Address, Link, withOnAction } from '../../components';
|
||||
import { editAccount } from '../../messaging';
|
||||
@@ -18,7 +19,7 @@ type Props = {
|
||||
|
||||
function Account ({ address, className, onAction }: Props) {
|
||||
const [isEditing, setEditing] = useState(false);
|
||||
const [editedname, setName] = useState(null as string | null);
|
||||
const [editedname, setName] = useState<string | null>(null);
|
||||
|
||||
const toggleEdit = (): void => {
|
||||
setEditing(!isEditing);
|
||||
@@ -37,20 +38,17 @@ function Account ({ address, className, onAction }: Props) {
|
||||
<Address
|
||||
address={address}
|
||||
className={className}
|
||||
name={
|
||||
isEditing
|
||||
? (
|
||||
<Name
|
||||
address={address}
|
||||
isFocussed
|
||||
label={null}
|
||||
onBlur={saveChanges}
|
||||
onChange={setName}
|
||||
/>
|
||||
)
|
||||
: undefined
|
||||
}
|
||||
>
|
||||
{isEditing && (
|
||||
<Name
|
||||
address={address}
|
||||
className='edit-name'
|
||||
isFocussed
|
||||
label={null}
|
||||
onBlur={saveChanges}
|
||||
onChange={setName}
|
||||
/>
|
||||
)}
|
||||
<ActionBar>
|
||||
<Link onClick={toggleEdit}>Edit</Link>
|
||||
<Link to={`/account/forget/${address}`}>Forget</Link>
|
||||
@@ -59,4 +57,11 @@ function Account ({ address, className, onAction }: Props) {
|
||||
);
|
||||
}
|
||||
|
||||
export default withOnAction(Account);
|
||||
export default withOnAction(styled(Account)`
|
||||
.edit-name {
|
||||
left: 4.75rem;
|
||||
position: absolute;
|
||||
right: 0.75rem;
|
||||
top: -0.5rem;
|
||||
}
|
||||
`);
|
||||
|
||||
@@ -15,9 +15,9 @@ type Props = {
|
||||
};
|
||||
|
||||
function Create ({ onAction }: Props) {
|
||||
const [account, setAccount] = useState(null as null | { address: string, seed: string });
|
||||
const [name, setName] = useState(null as string | null);
|
||||
const [password, setPassword] = useState(null as string | null);
|
||||
const [account, setAccount] = useState<null | { address: string, seed: string }>(null);
|
||||
const [name, setName] = useState<string | null>(null);
|
||||
const [password, setPassword] = useState<string | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
createSeed()
|
||||
|
||||
@@ -15,9 +15,9 @@ type Props = {
|
||||
};
|
||||
|
||||
function Import ({ onAction }: Props) {
|
||||
const [account, setAccount] = useState(null as null | { address: string, seed: string });
|
||||
const [name, setName] = useState(null as string | null);
|
||||
const [password, setPassword] = useState(null as string | null);
|
||||
const [account, setAccount] = useState<null | { address: string, seed: string }>(null);
|
||||
const [name, setName] = useState<string | null>(null);
|
||||
const [password, setPassword] = useState<string | null>(null);
|
||||
|
||||
const onChangeSeed = (seed: string): void => {
|
||||
validateSeed(seed)
|
||||
|
||||
@@ -21,9 +21,9 @@ import Signing from './Signing';
|
||||
type Props = {};
|
||||
|
||||
export default function Popup (props: Props) {
|
||||
const [accounts, setAccounts] = useState(null as null | Array<KeyringJson>);
|
||||
const [authRequests, setAuthRequests] = useState(null as null | Array<AuthorizeRequest>);
|
||||
const [signRequests, setSignRequests] = useState(null as null | Array<SigningRequest>);
|
||||
const [accounts, setAccounts] = useState<null | Array<KeyringJson>>(null);
|
||||
const [authRequests, setAuthRequests] = useState<null | Array<AuthorizeRequest>>(null);
|
||||
const [signRequests, setSignRequests] = useState<null | Array<SigningRequest>>(null);
|
||||
|
||||
const onAction = (to?: string): void => {
|
||||
// loads all accounts & requests (this is passed through to children to trigger changes)
|
||||
|
||||
@@ -32,9 +32,7 @@ function Address ({ accounts, address, children, className, isHidden, name, them
|
||||
return (
|
||||
<div className={className}>
|
||||
<Box className='details'>
|
||||
<div className='name'>
|
||||
<div className='content'>{name || (account && account.meta.name) || '<unknown>'}</div>
|
||||
</div>
|
||||
<div className='name'>{name || (account && account.meta.name) || '<unknown>'}</div>
|
||||
<div className='address'>{address || '<unknown>'}</div>
|
||||
<div className='children'>{children}</div>
|
||||
</Box>
|
||||
@@ -49,11 +47,11 @@ function Address ({ accounts, address, children, className, isHidden, name, them
|
||||
}
|
||||
|
||||
export default withAccounts(styled(Address)`
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
margin: ${defaults.boxMargin};
|
||||
padding: ${defaults.boxPadding};
|
||||
padding-left: 1rem;
|
||||
position: relative;
|
||||
|
||||
.details {
|
||||
margin: 0;
|
||||
@@ -70,13 +68,7 @@ export default withAccounts(styled(Address)`
|
||||
}
|
||||
|
||||
.name {
|
||||
.content {
|
||||
padding: 0 0 0.5rem 0;
|
||||
|
||||
input {
|
||||
margin: -0.5rem 0;
|
||||
}
|
||||
}
|
||||
padding-bottom: 0.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,28 +26,20 @@ function Input ({ className, defaultValue, label, isFocussed, isReadOnly, onBlur
|
||||
onChange && onChange(value.trim());
|
||||
};
|
||||
|
||||
const element = (
|
||||
<input
|
||||
autoFocus={isFocussed}
|
||||
defaultValue={defaultValue || undefined}
|
||||
readOnly={isReadOnly}
|
||||
onBlur={onBlur}
|
||||
onChange={_onChange}
|
||||
type={type}
|
||||
value={value}
|
||||
/>
|
||||
);
|
||||
|
||||
if (!label) {
|
||||
return <div className={className}>{element}</div>;
|
||||
}
|
||||
|
||||
return (
|
||||
<Label
|
||||
className={className}
|
||||
label={label}
|
||||
>
|
||||
{element}
|
||||
<input
|
||||
autoFocus={isFocussed}
|
||||
defaultValue={defaultValue || undefined}
|
||||
readOnly={isReadOnly}
|
||||
onBlur={onBlur}
|
||||
onChange={_onChange}
|
||||
type={type}
|
||||
value={value}
|
||||
/>
|
||||
</Label>
|
||||
);
|
||||
}
|
||||
@@ -78,7 +70,11 @@ export default styled(Input)`
|
||||
display: block;
|
||||
font-family: ${defaults.fontFamily};
|
||||
font-size: ${defaults.fontSize};
|
||||
padding: ${defaults.inputPadding};
|
||||
padding: ${({ label }) =>
|
||||
label
|
||||
? defaults.inputPaddingLabel
|
||||
: defaults.inputPadding
|
||||
};
|
||||
width: 100%;
|
||||
|
||||
&:read-only {
|
||||
|
||||
@@ -10,13 +10,13 @@ import defaults from './defaults';
|
||||
type Props = {
|
||||
children: React.ReactNode,
|
||||
className?: string,
|
||||
label: string
|
||||
label?: string | null
|
||||
};
|
||||
|
||||
function Label ({ children, className, label }: Props) {
|
||||
return (
|
||||
<div className={className}>
|
||||
<label>{label}</label>
|
||||
{label && <label>{label}</label>}
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
@@ -30,10 +30,13 @@ export default styled(Label)`
|
||||
font-size: ${defaults.fontSize};
|
||||
margin: ${defaults.boxMargin};
|
||||
padding: ${defaults.boxPadding};
|
||||
position: relative;
|
||||
|
||||
label {
|
||||
display: block;
|
||||
font-size: 0.9rem;
|
||||
margin-bottom: 0.25rem;
|
||||
font-size: 0.75rem;
|
||||
left: 1rem;
|
||||
position: absolute;
|
||||
top: 0.25rem;
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -64,7 +64,11 @@ export default styled(TextArea)`
|
||||
display: block;
|
||||
font-family: ${defaults.fontFamily};
|
||||
font-size: ${defaults.fontSize};
|
||||
padding: ${defaults.inputPadding};
|
||||
padding: ${({ label }) =>
|
||||
label
|
||||
? defaults.inputPaddingLabel
|
||||
: defaults.inputPadding
|
||||
};
|
||||
resize: none;
|
||||
width: 100%;
|
||||
|
||||
|
||||
@@ -10,10 +10,10 @@ const noop = (to?: string) => {
|
||||
// do nothing
|
||||
};
|
||||
|
||||
const AccountContext = React.createContext([] as AccountsFromCtx);
|
||||
const ActionContext = React.createContext(noop as OnActionFromCtx);
|
||||
const AuthorizeContext = React.createContext([] as AuthRequestsFromCtx);
|
||||
const SigningContext = React.createContext([] as SignRequestsFromCtx);
|
||||
const AccountContext = React.createContext<AccountsFromCtx>([]);
|
||||
const ActionContext = React.createContext<OnActionFromCtx>(noop);
|
||||
const AuthorizeContext = React.createContext<AuthRequestsFromCtx>([]);
|
||||
const SigningContext = React.createContext<SignRequestsFromCtx>([]);
|
||||
|
||||
export {
|
||||
AccountContext,
|
||||
|
||||
@@ -12,8 +12,8 @@ const defaults: { [index: string]: any } = {
|
||||
btnBg: TEXT_COLOR, // LINK_COLOR,
|
||||
btnBgDanger: DANGER_COLOR,
|
||||
btnBorder: `0 solid `,
|
||||
btnColor: '#fff',
|
||||
btnColorDanger: '#fff',
|
||||
btnColor: '#f5f6f7',
|
||||
btnColorDanger: '#f5f6f7',
|
||||
btnPadding: '0.75rem 1rem',
|
||||
boxBorder: 'none', // '0.25rem solid #e2e1e0',
|
||||
boxMargin: '0.75rem 0',
|
||||
@@ -26,6 +26,7 @@ const defaults: { [index: string]: any } = {
|
||||
hdrColor: LABEL_COLOR,
|
||||
inputBorder: '#ccc',
|
||||
inputPadding: '0.5rem 0.75rem',
|
||||
inputPaddingLabel: '1.25rem 0.75rem 0.5rem',
|
||||
labelColor: LABEL_COLOR,
|
||||
lineHeight: '1.25',
|
||||
linkColor: LINK_COLOR,
|
||||
|
||||
@@ -21,5 +21,5 @@ function Back ({ className, to = '/' }: Props) {
|
||||
}
|
||||
|
||||
export default styled(Back)`
|
||||
padding: 0.5rem;
|
||||
padding: 0 0.5rem;
|
||||
`;
|
||||
|
||||
@@ -2,13 +2,16 @@
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { AccountsFromCtx } from '../components/types';
|
||||
|
||||
import React, { useEffect, useState } from 'react';
|
||||
|
||||
import { Input } from '../components';
|
||||
import { AccountContext } from '../components/contexts';
|
||||
import { Input, withAccounts } from '../components';
|
||||
|
||||
type Props = {
|
||||
accounts: AccountsFromCtx,
|
||||
address?: string,
|
||||
className?: string,
|
||||
defaultValue?: string | null,
|
||||
isFocussed?: boolean,
|
||||
label?: string | null,
|
||||
@@ -18,38 +21,34 @@ type Props = {
|
||||
|
||||
const MIN_LENGTH = 3;
|
||||
|
||||
export default function Name ({ address, defaultValue, isFocussed, label = 'a descriptive name for this account', onBlur, onChange }: Props) {
|
||||
function Name ({ accounts, address, className, defaultValue, isFocussed, label = 'a descriptive name for this account', onBlur, onChange }: Props) {
|
||||
const [name, setName] = useState('');
|
||||
const account = accounts.find((account) => account.address === address);
|
||||
const startValue = (account && account.meta.name) || defaultValue;
|
||||
const isError = !name && startValue
|
||||
? false
|
||||
: (name.length < MIN_LENGTH);
|
||||
|
||||
useEffect(() => {
|
||||
onChange(
|
||||
(name.length >= MIN_LENGTH)
|
||||
name && (name.length >= MIN_LENGTH)
|
||||
? name
|
||||
: null
|
||||
);
|
||||
}, [name]);
|
||||
|
||||
return (
|
||||
<AccountContext.Consumer>
|
||||
{(accounts) => {
|
||||
const account = accounts.find((account) => account.address === address);
|
||||
const startValue = (account && account.meta.name) || defaultValue;
|
||||
const isError = !name && startValue
|
||||
? false
|
||||
: (name.length < MIN_LENGTH);
|
||||
|
||||
return (
|
||||
<Input
|
||||
defaultValue={startValue}
|
||||
isError={isError}
|
||||
isFocussed={isFocussed}
|
||||
label={label}
|
||||
onBlur={onBlur}
|
||||
onChange={setName}
|
||||
type='text'
|
||||
/>
|
||||
);
|
||||
}}
|
||||
</AccountContext.Consumer>
|
||||
<Input
|
||||
className={className}
|
||||
defaultValue={startValue}
|
||||
isError={isError}
|
||||
isFocussed={isFocussed}
|
||||
label={label}
|
||||
onBlur={onBlur}
|
||||
onChange={setName}
|
||||
type='text'
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export default withAccounts(Name);
|
||||
|
||||
Reference in New Issue
Block a user