Files
pezkuwi-ui/packages/react-identicon/src/Identicon.tsx
T
Jaco Greeff f003063b94 2021 (#424)
2021-01-03 11:46:19 +01:00

155 lines
3.6 KiB
TypeScript

// Copyright 2017-2021 @polkadot/react-identicon authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { Prefix } from '@polkadot/util-crypto/address/types';
import type { IdentityProps as Props, Props as ComponentProps } from './types';
import React from 'react';
import CopyToClipboard from 'react-copy-to-clipboard';
import styled from 'styled-components';
import { ICON_DEFAULT_HOST, settings } from '@polkadot/ui-settings';
import { isHex, isU8a, u8aToHex } from '@polkadot/util';
import { decodeAddress, encodeAddress, ethereumEncode } from '@polkadot/util-crypto';
import { Beachball, Empty, Ethereum, Jdenticon, Polkadot } from './icons';
const Fallback = Beachball;
interface State {
address: string;
publicKey: string;
}
const DEFAULT_SIZE = 64;
const Components: Record<string, React.ComponentType<ComponentProps>> = {
beachball: Beachball,
empty: Empty,
ethereum: Ethereum,
jdenticon: Jdenticon,
polkadot: Polkadot,
substrate: Jdenticon
};
const Wrapper = styled.div`
cursor: copy;
display: inline-block;
line-height: 0;
> .container {
position: relative;
> div,
> svg {
position: relative;
}
&.highlight:before {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
border-radius: 50%;
box-shadow: 0 0 5px 2px #aaa;
content: '';
}
}
`;
class BaseIcon extends React.PureComponent<Props, State> {
public state: State = {
address: '',
publicKey: '0x'
};
private static prefix?: Prefix = undefined;
public static setDefaultPrefix (prefix: Prefix): void {
BaseIcon.prefix = prefix;
}
public static getDerivedStateFromProps ({ prefix = BaseIcon.prefix, theme, value }: Props, prevState: State): State | null {
if (theme === 'ethereum') {
const address = isU8a(value)
? ethereumEncode(value)
: value || '';
return { address, publicKey: '' };
}
try {
const address = isU8a(value) || isHex(value)
? encodeAddress(value, prefix)
: (value || '');
const publicKey = u8aToHex(decodeAddress(address, false, prefix));
return address === prevState.address
? null
: {
address,
publicKey
};
} catch (error) {
return {
address: '',
publicKey: '0x'
};
}
}
public render (): React.ReactNode {
const { address } = this.state;
const wrapped = this.getWrapped(this.state, this.props);
return !address
? wrapped
: (
<CopyToClipboard
onCopy={this.onCopy}
text={address}
>
{wrapped}
</CopyToClipboard>
);
}
private getWrapped ({ address, publicKey }: State, { Custom }: Props): React.ReactNode {
const { className = '', isAlternative, isHighlight, size = DEFAULT_SIZE, style, theme = settings.icon } = this.props;
const Component = !address
? Empty
: Custom || Components[theme === 'default' ? ICON_DEFAULT_HOST : theme] || Fallback;
return (
<Wrapper
className={`ui--IdentityIcon ${className}`}
key={address}
style={style}
>
<Component
address={address}
className={isHighlight ? 'highlight' : ''}
isAlternative={isAlternative}
publicKey={publicKey}
size={size}
/>
</Wrapper>
);
}
private onCopy = (): void => {
const { onCopy } = this.props;
const { address } = this.state;
if (address && onCopy) {
onCopy(address);
}
}
}
function Icon (props: Props): React.ReactElement<Props> {
return <BaseIcon {...props} />;
}
export const Identicon = React.memo(Icon);