diff --git a/packages/react-identicon/src/icons/Jdenticon.tsx b/packages/react-identicon/src/icons/Jdenticon.tsx index 77062734..ece29e54 100644 --- a/packages/react-identicon/src/icons/Jdenticon.tsx +++ b/packages/react-identicon/src/icons/Jdenticon.tsx @@ -4,15 +4,18 @@ import type { Props } from '../types'; import * as jdenticon from 'jdenticon'; -import React from 'react'; +import React, { useMemo } from 'react'; function Identicon ({ className = '', publicKey, size, style }: Props): React.ReactElement { + const html = useMemo( + () => ({ __html: jdenticon.toSvg(publicKey.substr(2), size) }), + [publicKey, size] + ); + return (
); diff --git a/packages/react-identicon/src/icons/Polkadot.tsx b/packages/react-identicon/src/icons/Polkadot.tsx index 6aa7ff0d..c5ba86e9 100644 --- a/packages/react-identicon/src/icons/Polkadot.tsx +++ b/packages/react-identicon/src/icons/Polkadot.tsx @@ -19,7 +19,7 @@ import type { Circle } from '@polkadot/ui-shared/icons/types'; import type { Props } from '../types'; -import React from 'react'; +import React, { useMemo } from 'react'; import { polkadotIcon } from '@polkadot/ui-shared'; @@ -36,6 +36,11 @@ function renderCircle ({ cx, cy, fill, r }: Circle, key: number): React.ReactNod } function Identicon ({ address, className = '', isAlternative = false, size, style }: Props): React.ReactElement { + const circles = useMemo( + () => polkadotIcon(address, { isAlternative }), + [address, isAlternative] + ); + return ( - {polkadotIcon(address, { isAlternative }).map(renderCircle)} + {circles.map(renderCircle)} ); } diff --git a/packages/reactnative-identicon/src/icons/Polkadot.tsx b/packages/reactnative-identicon/src/icons/Polkadot.tsx index 7237e71b..0e0e675f 100644 --- a/packages/reactnative-identicon/src/icons/Polkadot.tsx +++ b/packages/reactnative-identicon/src/icons/Polkadot.tsx @@ -4,7 +4,7 @@ import type { Circle as CircleType } from '@polkadot/ui-shared/icons/types'; import type { Props } from '../types'; -import React from 'react'; +import React, { useMemo } from 'react'; import { View } from 'react-native'; import Svg, { Circle as SvgCircle } from 'react-native-svg'; @@ -23,6 +23,11 @@ function renderCircle ({ cx, cy, fill, r }: CircleType, key: number): React.Reac } export default function Identicon ({ address, isAlternative = false, size }: Props): React.ReactElement { + const circles = useMemo( + () => polkadotIcon(address, { isAlternative }), + [address, isAlternative] + ); + return ( - {polkadotIcon(address, { isAlternative }).map(renderCircle)} + {circles.map(renderCircle)} ); diff --git a/packages/ui-shared/src/icons/polkadot.ts b/packages/ui-shared/src/icons/polkadot.ts index 7878583e..85075cf1 100644 --- a/packages/ui-shared/src/icons/polkadot.ts +++ b/packages/ui-shared/src/icons/polkadot.ts @@ -22,7 +22,6 @@ const blake2 = (value: Uint8Array): Uint8Array => const S = 64; const C = S / 2; const Z = S / 64 * 5; -const ZERO = blake2(new Uint8Array(32)); /* eslint-disable sort-keys */ const SCHEMA: { [index: string]: Scheme } = { @@ -43,6 +42,8 @@ const OUTER_CIRCLE: Circle = { r: C }; +let zeroHash: Uint8Array = new Uint8Array(); + function getRotation (isSixPoint: boolean): { r: number; ro2: number; r3o4: number; ro4: number; rroot3o2: number; rroot3o4: number } { const r = isSixPoint ? (C / 8 * 5) @@ -98,7 +99,11 @@ function findScheme (d: number): Scheme { } function addressToId (address: string): Uint8Array { - return blake2(decodeAddress(address)).map((x, i): number => (x + 256 - ZERO[i]) % 256); + if (!zeroHash.length) { + zeroHash = blake2(new Uint8Array(32)); + } + + return blake2(decodeAddress(address)).map((x, i) => (x + 256 - zeroHash[i]) % 256); } function getColors (address: string): string[] { @@ -132,10 +137,19 @@ function getColors (address: string): string[] { * @description Generate a array of the circles that make up an identicon */ export function polkadotIcon (address: string, { isAlternative }: Options): Circle[] { - const colors = getColors(address); + const xy = getCircleXY(isAlternative); + let colors: string[]; + + try { + // in some cases, e.g. RN where crypto may not be initialized, chaos can + // happen when hashing, in these cases we just fill with a placeholder + colors = getColors(address); + } catch { + colors = new Array(xy.length).fill('#ddd'); + } return [OUTER_CIRCLE].concat( - getCircleXY(isAlternative).map(([cx, cy], index): Circle => ({ + xy.map(([cx, cy], index): Circle => ({ cx, cy, fill: colors[index], r: Z })) );