Bumps w/ eslint (#338)
* Bumps w/ eslint * Additional * Additional * Additional * Additional * Additional * Linting done, tsc fixes remain * Final round
This commit is contained in:
parent
f313d13a44
commit
837fb52a3a
@ -6,11 +6,11 @@
|
|||||||
import chrome from 'sinon-chrome';
|
import chrome from 'sinon-chrome';
|
||||||
|
|
||||||
class MessagingFake {
|
class MessagingFake {
|
||||||
private listeners: any = [];
|
private listeners: ((...params: unknown[]) => unknown)[] = [];
|
||||||
|
|
||||||
get onMessage (): any {
|
get onMessage (): any {
|
||||||
return {
|
return {
|
||||||
addListener: (cb: any): any => this.listeners.push(cb)
|
addListener: (cb: (...params: unknown[]) => unknown) => this.listeners.push(cb)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -20,8 +20,8 @@ class MessagingFake {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
postMessage (data: any): void {
|
postMessage (data: unknown): void {
|
||||||
this.listeners.forEach((cb: any) => cb.call(this, data));
|
this.listeners.forEach((cb) => cb.call(this, data));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -29,7 +29,7 @@ const messagingFake = new MessagingFake();
|
|||||||
|
|
||||||
chrome.runtime.connect.returns(messagingFake);
|
chrome.runtime.connect.returns(messagingFake);
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any,@typescript-eslint/no-unsafe-member-access
|
||||||
(window as any).chrome = chrome;
|
(window as any).chrome = chrome;
|
||||||
|
|
||||||
export default chrome;
|
export default chrome;
|
||||||
|
|||||||
12
package.json
12
package.json
@ -7,9 +7,9 @@
|
|||||||
"packages/*"
|
"packages/*"
|
||||||
],
|
],
|
||||||
"resolutions": {
|
"resolutions": {
|
||||||
"@polkadot/api": "^1.14.1",
|
"@polkadot/api": "^1.15.1",
|
||||||
"@polkadot/keyring": "^2.10.1",
|
"@polkadot/keyring": "^2.10.1",
|
||||||
"@polkadot/types": "^1.14.1",
|
"@polkadot/types": "^1.15.1",
|
||||||
"@polkadot/util": "^2.10.1",
|
"@polkadot/util": "^2.10.1",
|
||||||
"@polkadot/util-crypto": "^2.10.1",
|
"@polkadot/util-crypto": "^2.10.1",
|
||||||
"babel-core": "^7.0.0-bridge.0"
|
"babel-core": "^7.0.0-bridge.0"
|
||||||
@ -30,12 +30,12 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.9.6",
|
"@babel/core": "^7.9.6",
|
||||||
"@polkadot/dev": "^0.53.5",
|
"@polkadot/dev": "^0.54.1",
|
||||||
"@polkadot/typegen": "^1.14.1",
|
"@polkadot/typegen": "^1.15.1",
|
||||||
"@types/jest": "^25.2.2",
|
"@types/jest": "^25.2.3",
|
||||||
"copy-webpack-plugin": "^5.1.1",
|
"copy-webpack-plugin": "^5.1.1",
|
||||||
"sinon-chrome": "^3.0.1",
|
"sinon-chrome": "^3.0.1",
|
||||||
"stylelint": "^13.3.3",
|
"stylelint": "^13.5.0",
|
||||||
"stylelint-config-recommended": "^3.0.0",
|
"stylelint-config-recommended": "^3.0.0",
|
||||||
"stylelint-config-styled-components": "^0.1.1"
|
"stylelint-config-styled-components": "^0.1.1"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,9 +6,9 @@
|
|||||||
"license": "Apache-2",
|
"license": "Apache-2",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.9.6",
|
"@babel/runtime": "^7.9.6",
|
||||||
"@polkadot/api": "^1.14.1",
|
"@polkadot/api": "^1.15.1",
|
||||||
"@polkadot/extension-inject": "0.26.0-beta.2",
|
"@polkadot/extension-inject": "0.26.0-beta.2",
|
||||||
"@polkadot/keyring": "^2.10.1",
|
"@polkadot/keyring": "^2.10.1",
|
||||||
"@polkadot/ui-keyring": "^0.53.1"
|
"@polkadot/ui-keyring": "^0.54.0-beta.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,12 +13,15 @@ import chrome from '@polkadot/extension-inject/chrome';
|
|||||||
|
|
||||||
import { MetadataStore } from '../../stores';
|
import { MetadataStore } from '../../stores';
|
||||||
|
|
||||||
interface AuthRequest {
|
interface Resolver <T> {
|
||||||
|
reject: (error: Error) => void;
|
||||||
|
resolve: (result: T) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface AuthRequest extends Resolver<boolean> {
|
||||||
id: string;
|
id: string;
|
||||||
idStr: string;
|
idStr: string;
|
||||||
request: RequestAuthorizeTab;
|
request: RequestAuthorizeTab;
|
||||||
resolve: (result: boolean) => void;
|
|
||||||
reject: (error: Error) => void;
|
|
||||||
url: string;
|
url: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -30,11 +33,9 @@ type AuthUrls = Record<string, {
|
|||||||
url: string;
|
url: string;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
interface MetaRequest {
|
interface MetaRequest extends Resolver<boolean> {
|
||||||
id: string;
|
id: string;
|
||||||
request: MetadataDef;
|
request: MetadataDef;
|
||||||
resolve: (result: boolean) => void;
|
|
||||||
reject: (error: Error) => void;
|
|
||||||
url: string;
|
url: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,12 +48,10 @@ type Providers = Record<string, {
|
|||||||
start: () => ProviderInterface;
|
start: () => ProviderInterface;
|
||||||
}>
|
}>
|
||||||
|
|
||||||
interface SignRequest {
|
interface SignRequest extends Resolver<ResponseSigning> {
|
||||||
account: AccountJson;
|
account: AccountJson;
|
||||||
id: string;
|
id: string;
|
||||||
request: RequestSign;
|
request: RequestSign;
|
||||||
resolve: (result: ResponseSigning) => void;
|
|
||||||
reject: (error: Error) => void;
|
|
||||||
url: string;
|
url: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,7 +80,7 @@ export default class State {
|
|||||||
readonly #metaStore = new MetadataStore();
|
readonly #metaStore = new MetadataStore();
|
||||||
|
|
||||||
// Map of providers currently injected in tabs
|
// Map of providers currently injected in tabs
|
||||||
readonly #injectedProviders: Map<chrome.runtime.Port, ProviderInterface> = new Map();
|
readonly #injectedProviders = new Map<chrome.runtime.Port, ProviderInterface>();
|
||||||
|
|
||||||
readonly #metaRequests: Record<string, MetaRequest> = {};
|
readonly #metaRequests: Record<string, MetaRequest> = {};
|
||||||
|
|
||||||
@ -155,8 +154,8 @@ export default class State {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private authComplete = (id: string, fn: Function): (result: boolean | Error) => void => {
|
private authComplete = (id: string, resolve: (result: boolean) => void, reject: (error: Error) => void): Resolver<boolean> => {
|
||||||
return (result: boolean | Error): void => {
|
const complete = (result: boolean | Error) => {
|
||||||
const isAllowed = result === true;
|
const isAllowed = result === true;
|
||||||
const { idStr, request: { origin }, url } = this.#authRequests[id];
|
const { idStr, request: { origin }, url } = this.#authRequests[id];
|
||||||
|
|
||||||
@ -170,26 +169,53 @@ export default class State {
|
|||||||
|
|
||||||
delete this.#authRequests[id];
|
delete this.#authRequests[id];
|
||||||
this.updateIconAuth(true);
|
this.updateIconAuth(true);
|
||||||
|
};
|
||||||
|
|
||||||
fn(result);
|
return {
|
||||||
|
reject: (error: Error): void => {
|
||||||
|
complete(error);
|
||||||
|
reject(error);
|
||||||
|
},
|
||||||
|
resolve: (result: boolean): void => {
|
||||||
|
complete(result);
|
||||||
|
resolve(result);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private metaComplete = (id: string, fn: Function): (result: boolean | Error) => void => {
|
private metaComplete = (id: string, resolve: (result: boolean) => void, reject: (error: Error) => void): Resolver<boolean> => {
|
||||||
return (result: boolean | Error): void => {
|
const complete = (): void => {
|
||||||
delete this.#metaRequests[id];
|
delete this.#metaRequests[id];
|
||||||
this.updateIconMeta(true);
|
this.updateIconMeta(true);
|
||||||
|
};
|
||||||
|
|
||||||
fn(result);
|
return {
|
||||||
|
reject: (error: Error): void => {
|
||||||
|
complete();
|
||||||
|
reject(error);
|
||||||
|
},
|
||||||
|
resolve: (result: boolean): void => {
|
||||||
|
complete();
|
||||||
|
resolve(result);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private signComplete = (id: string, fn: Function): (result: ResponseSigning | Error) => void => {
|
private signComplete = (id: string, resolve: (result: ResponseSigning) => void, reject: (error: Error) => void): Resolver<ResponseSigning> => {
|
||||||
return (result: ResponseSigning | Error): void => {
|
const complete = (): void => {
|
||||||
delete this.#signRequests[id];
|
delete this.#signRequests[id];
|
||||||
this.updateIconSign(true);
|
this.updateIconSign(true);
|
||||||
|
};
|
||||||
|
|
||||||
fn(result);
|
return {
|
||||||
|
reject: (error: Error): void => {
|
||||||
|
complete();
|
||||||
|
reject(error);
|
||||||
|
},
|
||||||
|
resolve: (result: ResponseSigning): void => {
|
||||||
|
complete();
|
||||||
|
resolve(result);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -248,11 +274,10 @@ export default class State {
|
|||||||
const id = getId();
|
const id = getId();
|
||||||
|
|
||||||
this.#authRequests[id] = {
|
this.#authRequests[id] = {
|
||||||
|
...this.authComplete(id, resolve, reject),
|
||||||
id,
|
id,
|
||||||
idStr,
|
idStr,
|
||||||
reject: this.authComplete(id, reject),
|
|
||||||
request,
|
request,
|
||||||
resolve: this.authComplete(id, resolve),
|
|
||||||
url
|
url
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -275,10 +300,9 @@ export default class State {
|
|||||||
const id = getId();
|
const id = getId();
|
||||||
|
|
||||||
this.#metaRequests[id] = {
|
this.#metaRequests[id] = {
|
||||||
|
...this.metaComplete(id, resolve, reject),
|
||||||
id,
|
id,
|
||||||
reject: this.metaComplete(id, reject),
|
|
||||||
request,
|
request,
|
||||||
resolve: this.metaComplete(id, resolve),
|
|
||||||
url
|
url
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -313,7 +337,7 @@ export default class State {
|
|||||||
|
|
||||||
assert(provider, 'Cannot call pub(rpc.subscribe) before provider is set');
|
assert(provider, 'Cannot call pub(rpc.subscribe) before provider is set');
|
||||||
|
|
||||||
return provider.send(request.method, request.params);
|
return provider.send(request.method, request.params) as Promise<JsonRpcResponse>;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start a provider, return its meta
|
// Start a provider, return its meta
|
||||||
@ -378,11 +402,10 @@ export default class State {
|
|||||||
|
|
||||||
return new Promise((resolve, reject): void => {
|
return new Promise((resolve, reject): void => {
|
||||||
this.#signRequests[id] = {
|
this.#signRequests[id] = {
|
||||||
|
...this.signComplete(id, resolve, reject),
|
||||||
account,
|
account,
|
||||||
id,
|
id,
|
||||||
reject: this.signComplete(id, reject),
|
|
||||||
request,
|
request,
|
||||||
resolve: this.signComplete(id, resolve),
|
|
||||||
url
|
url
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -108,7 +108,7 @@ export default class Tabs {
|
|||||||
|
|
||||||
port.onDisconnect.addListener((): void => {
|
port.onDisconnect.addListener((): void => {
|
||||||
unsubscribe(id);
|
unsubscribe(id);
|
||||||
this.rpcUnsubscribe({ ...request, subscriptionId }, port);
|
this.rpcUnsubscribe({ ...request, subscriptionId }, port).catch(console.error);
|
||||||
});
|
});
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@ -39,7 +39,7 @@ export default function handler<TMessageType extends MessageTypes> ({ id, messag
|
|||||||
|
|
||||||
port.postMessage({ id, response });
|
port.postMessage({ id, response });
|
||||||
})
|
})
|
||||||
.catch((error): void => {
|
.catch((error: Error): void => {
|
||||||
console.log(`[err] ${source}:: ${error.message}`);
|
console.log(`[err] ${source}:: ${error.message}`);
|
||||||
|
|
||||||
// only send message back to port if it's still connected
|
// only send message back to port if it's still connected
|
||||||
|
|||||||
@ -12,8 +12,7 @@ const subscriptions: Subscriptions = {};
|
|||||||
export function createSubscription<TMessageType extends MessageTypesWithSubscriptions> (id: string, port: chrome.runtime.Port): (data: SubscriptionMessageTypes[TMessageType]) => void {
|
export function createSubscription<TMessageType extends MessageTypesWithSubscriptions> (id: string, port: chrome.runtime.Port): (data: SubscriptionMessageTypes[TMessageType]) => void {
|
||||||
subscriptions[id] = port;
|
subscriptions[id] = port;
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
return (subscription: unknown): void => {
|
||||||
return (subscription: any): void => {
|
|
||||||
if (subscriptions[id]) {
|
if (subscriptions[id]) {
|
||||||
port.postMessage({ id, subscription });
|
port.postMessage({ id, subscription });
|
||||||
}
|
}
|
||||||
|
|||||||
@ -199,8 +199,7 @@ export type RequestAccountSubscribe = null;
|
|||||||
|
|
||||||
export interface RequestRpcSend {
|
export interface RequestRpcSend {
|
||||||
method: string;
|
method: string;
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
params: unknown[];
|
||||||
params: any[];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RequestRpcSubscribe extends RequestRpcSend {
|
export interface RequestRpcSubscribe extends RequestRpcSend {
|
||||||
|
|||||||
@ -17,8 +17,7 @@ export default class Accounts implements InjectedAccounts {
|
|||||||
return sendRequest('pub(accounts.list)');
|
return sendRequest('pub(accounts.list)');
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
public subscribe (cb: (accounts: InjectedAccount[]) => unknown): Unsubcall {
|
||||||
public subscribe (cb: (accounts: InjectedAccount[]) => any): Unsubcall {
|
|
||||||
sendRequest('pub(accounts.subscribe)', null, cb)
|
sendRequest('pub(accounts.subscribe)', null, cb)
|
||||||
.catch((error: Error) => console.error(error));
|
.catch((error: Error) => console.error(error));
|
||||||
|
|
||||||
|
|||||||
@ -12,8 +12,7 @@ import { ProviderList, ProviderMeta, InjectedProvider } from '@polkadot/extensio
|
|||||||
|
|
||||||
const l = logger('PostMessageProvider');
|
const l = logger('PostMessageProvider');
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
type CallbackHandler = (error?: null | Error, value?: unknown) => void;
|
||||||
type CallbackHandler = (error?: null | Error, value?: any) => void;
|
|
||||||
|
|
||||||
// Same as https://github.com/polkadot-js/api/blob/57ca9a9c3204339e1e1f693fcacc33039868dc27/packages/rpc-provider/src/ws/Provider.ts#L17
|
// Same as https://github.com/polkadot-js/api/blob/57ca9a9c3204339e1e1f693fcacc33039868dc27/packages/rpc-provider/src/ws/Provider.ts#L17
|
||||||
interface SubscriptionHandler {
|
interface SubscriptionHandler {
|
||||||
@ -100,24 +99,20 @@ export default class PostMessageProvider implements InjectedProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
public send (method: string, params: any[], subscription?: SubscriptionHandler): Promise<any> {
|
public async send (method: string, params: unknown[], subscription?: SubscriptionHandler): Promise<any> {
|
||||||
if (subscription) {
|
if (subscription) {
|
||||||
const { callback, type } = subscription;
|
const { callback, type } = subscription;
|
||||||
|
|
||||||
return sendRequest(
|
const id = await sendRequest('pub(rpc.subscribe)', { method, params, type }, (res): void => {
|
||||||
'pub(rpc.subscribe)',
|
subscription.callback(null, res);
|
||||||
{ method, params, type },
|
|
||||||
(res) => {
|
|
||||||
subscription.callback(null, res);
|
|
||||||
}
|
|
||||||
).then((id): number => {
|
|
||||||
this.#subscriptions[`${type}::${id}`] = callback;
|
|
||||||
|
|
||||||
return id;
|
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
return sendRequest('pub(rpc.send)', { method, params });
|
this.#subscriptions[`${type}::${id}`] = callback;
|
||||||
|
|
||||||
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return sendRequest('pub(rpc.send)', { method, params });
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -130,6 +125,7 @@ export default class PostMessageProvider implements InjectedProvider {
|
|||||||
|
|
||||||
const meta = await sendRequest('pub(rpc.startProvider)', key);
|
const meta = await sendRequest('pub(rpc.startProvider)', key);
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||||
sendRequest('pub(rpc.subscribeConnected)', null, (connected) => {
|
sendRequest('pub(rpc.subscribeConnected)', null, (connected) => {
|
||||||
this.#isConnected = connected;
|
this.#isConnected = connected;
|
||||||
|
|
||||||
@ -145,11 +141,8 @@ export default class PostMessageProvider implements InjectedProvider {
|
|||||||
return meta;
|
return meta;
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
public subscribe (type: string, method: string, params: unknown[], callback: AnyFunction): Promise<number> {
|
||||||
public async subscribe (type: string, method: string, params: any[], callback: AnyFunction): Promise<number> {
|
return this.send(method, params, { callback, type }) as Promise<number>;
|
||||||
const id = await this.send(method, params, { callback, type });
|
|
||||||
|
|
||||||
return id as number;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -170,8 +163,6 @@ export default class PostMessageProvider implements InjectedProvider {
|
|||||||
|
|
||||||
delete this.#subscriptions[subscription];
|
delete this.#subscriptions[subscription];
|
||||||
|
|
||||||
const result = await this.send(method, [id]);
|
return this.send(method, [id]) as Promise<boolean>;
|
||||||
|
|
||||||
return result as boolean;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,7 +15,7 @@ import Injected from './Injected';
|
|||||||
|
|
||||||
export interface Handler {
|
export interface Handler {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
resolve: (data: any) => void;
|
resolve: (data?: any) => void;
|
||||||
reject: (error: Error) => void;
|
reject: (error: Error) => void;
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
subscriber?: (data: any) => void;
|
subscriber?: (data: any) => void;
|
||||||
@ -32,8 +32,7 @@ export function sendMessage<TMessageType extends MessageTypesWithNullRequest>(me
|
|||||||
export function sendMessage<TMessageType extends MessageTypesWithNoSubscriptions>(message: TMessageType, request: RequestTypes[TMessageType]): Promise<ResponseTypes[TMessageType]>;
|
export function sendMessage<TMessageType extends MessageTypesWithNoSubscriptions>(message: TMessageType, request: RequestTypes[TMessageType]): Promise<ResponseTypes[TMessageType]>;
|
||||||
export function sendMessage<TMessageType extends MessageTypesWithSubscriptions>(message: TMessageType, request: RequestTypes[TMessageType], subscriber: (data: SubscriptionMessageTypes[TMessageType]) => void): Promise<ResponseTypes[TMessageType]>;
|
export function sendMessage<TMessageType extends MessageTypesWithSubscriptions>(message: TMessageType, request: RequestTypes[TMessageType], subscriber: (data: SubscriptionMessageTypes[TMessageType]) => void): Promise<ResponseTypes[TMessageType]>;
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
export function sendMessage<TMessageType extends MessageTypes> (message: TMessageType, request?: RequestTypes[TMessageType], subscriber?: (data: unknown) => void): Promise<ResponseTypes[TMessageType]> {
|
||||||
export function sendMessage<TMessageType extends MessageTypes> (message: TMessageType, request?: RequestTypes[TMessageType], subscriber?: (data: any) => void): Promise<ResponseTypes[TMessageType]> {
|
|
||||||
return new Promise((resolve, reject): void => {
|
return new Promise((resolve, reject): void => {
|
||||||
const id = `${Date.now()}.${++idCounter}`;
|
const id = `${Date.now()}.${++idCounter}`;
|
||||||
|
|
||||||
@ -57,8 +56,7 @@ export async function enable (origin: string): Promise<Injected> {
|
|||||||
return new Injected(sendMessage);
|
return new Injected(sendMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
export function handleResponse<TMessageType extends MessageTypes> (data: TransportResponseMessage<TMessageType> & { subscription?: string }): void {
|
||||||
export function handleResponse<TMessageType extends MessageTypes> (data: TransportResponseMessage<TMessageType> & { subscription?: any }): void {
|
|
||||||
const handler = handlers[data.id];
|
const handler = handlers[data.id];
|
||||||
|
|
||||||
if (!handler) {
|
if (!handler) {
|
||||||
@ -72,6 +70,7 @@ export function handleResponse<TMessageType extends MessageTypes> (data: Transpo
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (data.subscription) {
|
if (data.subscription) {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||||
(handler.subscriber as Function)(data.subscription);
|
(handler.subscriber as Function)(data.subscription);
|
||||||
} else if (data.error) {
|
} else if (data.error) {
|
||||||
handler.reject(new Error(data.error));
|
handler.reject(new Error(data.error));
|
||||||
|
|||||||
@ -6,7 +6,7 @@ import { KeyringStore, KeyringJson } from '@polkadot/ui-keyring/types';
|
|||||||
|
|
||||||
import BaseStore from './Base';
|
import BaseStore from './Base';
|
||||||
|
|
||||||
export default class AccountsStore extends BaseStore implements KeyringStore {
|
export default class AccountsStore extends BaseStore<KeyringJson> implements KeyringStore {
|
||||||
constructor () {
|
constructor () {
|
||||||
super(null);
|
super(null);
|
||||||
}
|
}
|
||||||
@ -15,22 +15,22 @@ export default class AccountsStore extends BaseStore implements KeyringStore {
|
|||||||
super.all(cb);
|
super.all(cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
public get (key: string, cb: (value: KeyringJson) => void): void {
|
public get (key: string, update: (value: KeyringJson) => void): void {
|
||||||
super.get(key, cb);
|
super.get(key, update);
|
||||||
}
|
}
|
||||||
|
|
||||||
public remove (key: string, cb?: () => void): void {
|
public remove (key: string, update?: () => void): void {
|
||||||
super.remove(key, cb);
|
super.remove(key, update);
|
||||||
}
|
}
|
||||||
|
|
||||||
public set (key: string, value: KeyringJson, cb?: () => void): void {
|
public set (key: string, value: KeyringJson, update?: () => void): void {
|
||||||
// shortcut, don't save testing accounts in extension storage
|
// shortcut, don't save testing accounts in extension storage
|
||||||
if (key.startsWith('account:') && value.meta && value.meta.isTesting) {
|
if (key.startsWith('account:') && value.meta && value.meta.isTesting) {
|
||||||
cb && cb();
|
update && update();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
super.set(key, value, cb);
|
super.set(key, value, update);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,8 +4,7 @@
|
|||||||
|
|
||||||
import chrome from '@polkadot/extension-inject/chrome';
|
import chrome from '@polkadot/extension-inject/chrome';
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
type StoreValue = Record<string, unknown>;
|
||||||
type StoreValue = Record<string, any>;
|
|
||||||
|
|
||||||
const lastError = (type: string): void => {
|
const lastError = (type: string): void => {
|
||||||
const error = chrome.runtime.lastError;
|
const error = chrome.runtime.lastError;
|
||||||
@ -15,15 +14,14 @@ const lastError = (type: string): void => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export default abstract class BaseStore {
|
export default abstract class BaseStore <T> {
|
||||||
#prefix: string;
|
#prefix: string;
|
||||||
|
|
||||||
constructor (prefix: string | null) {
|
constructor (prefix: string | null) {
|
||||||
this.#prefix = prefix ? `${prefix}:` : '';
|
this.#prefix = prefix ? `${prefix}:` : '';
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
public all (update: (key: string, value: T) => void): void {
|
||||||
public all (cb: (key: string, value: any) => void): void {
|
|
||||||
chrome.storage.local.get(null, (result: StoreValue): void => {
|
chrome.storage.local.get(null, (result: StoreValue): void => {
|
||||||
lastError('all');
|
lastError('all');
|
||||||
|
|
||||||
@ -31,41 +29,38 @@ export default abstract class BaseStore {
|
|||||||
.entries(result)
|
.entries(result)
|
||||||
.filter(([key]) => key.startsWith(this.#prefix))
|
.filter(([key]) => key.startsWith(this.#prefix))
|
||||||
.forEach(([key, value]): void => {
|
.forEach(([key, value]): void => {
|
||||||
cb(key.replace(this.#prefix, ''), value);
|
update(key.replace(this.#prefix, ''), value as T);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
public get (_key: string, update: (value: T) => void): void {
|
||||||
public get (_key: string, cb: (value: any) => void): void {
|
|
||||||
const key = `${this.#prefix}${_key}`;
|
const key = `${this.#prefix}${_key}`;
|
||||||
|
|
||||||
chrome.storage.local.get([key], (result: StoreValue): void => {
|
chrome.storage.local.get([key], (result: StoreValue): void => {
|
||||||
lastError('get');
|
lastError('get');
|
||||||
|
|
||||||
cb(result[key]);
|
update(result[key] as T);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
public remove (_key: string, update?: () => void): void {
|
||||||
public remove (_key: string, cb?: () => void): void {
|
|
||||||
const key = `${this.#prefix}${_key}`;
|
const key = `${this.#prefix}${_key}`;
|
||||||
|
|
||||||
chrome.storage.local.remove(key, (): void => {
|
chrome.storage.local.remove(key, (): void => {
|
||||||
lastError('remove');
|
lastError('remove');
|
||||||
|
|
||||||
cb && cb();
|
update && update();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
public set (_key: string, value: T, update?: () => void): void {
|
||||||
public set (_key: string, value: any, cb?: () => void): void {
|
|
||||||
const key = `${this.#prefix}${_key}`;
|
const key = `${this.#prefix}${_key}`;
|
||||||
|
|
||||||
chrome.storage.local.set({ [key]: value }, (): void => {
|
chrome.storage.local.set({ [key]: value }, (): void => {
|
||||||
lastError('set');
|
lastError('set');
|
||||||
|
|
||||||
cb && cb();
|
update && update();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,7 +6,7 @@ import { MetadataDef } from '@polkadot/extension-inject/types';
|
|||||||
|
|
||||||
import BaseStore from './Base';
|
import BaseStore from './Base';
|
||||||
|
|
||||||
export default class MetadataStore extends BaseStore {
|
export default class MetadataStore extends BaseStore<MetadataDef> {
|
||||||
constructor () {
|
constructor () {
|
||||||
super('metadata');
|
super('metadata');
|
||||||
}
|
}
|
||||||
@ -15,15 +15,15 @@ export default class MetadataStore extends BaseStore {
|
|||||||
super.all(cb);
|
super.all(cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
public get (key: string, cb: (value: MetadataDef) => void): void {
|
public get (key: string, update: (value: MetadataDef) => void): void {
|
||||||
super.get(key, cb);
|
super.get(key, update);
|
||||||
}
|
}
|
||||||
|
|
||||||
public remove (key: string, cb?: () => void): void {
|
public remove (key: string, update?: () => void): void {
|
||||||
super.remove(key, cb);
|
super.remove(key, update);
|
||||||
}
|
}
|
||||||
|
|
||||||
public set (key: string, value: MetadataDef, cb?: () => void): void {
|
public set (key: string, value: MetadataDef, update?: () => void): void {
|
||||||
super.set(key, value, cb);
|
super.set(key, value, update);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
13
packages/extension-base/src/types.ts
Normal file
13
packages/extension-base/src/types.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
// Copyright 2019-2020 @polkadot/extension authors & contributors
|
||||||
|
// This software may be modified and distributed under the terms
|
||||||
|
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||||
|
|
||||||
|
export interface Message extends MessageEvent {
|
||||||
|
data: {
|
||||||
|
error?: string;
|
||||||
|
id: string;
|
||||||
|
origin: string;
|
||||||
|
response?: string;
|
||||||
|
subscription?: string;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -19,8 +19,7 @@ function metadataExpand (definition: MetadataDef): Chain {
|
|||||||
const { chain, genesisHash, icon, metaCalls, specVersion, ss58Format, tokenDecimals, tokenSymbol, types } = definition;
|
const { chain, genesisHash, icon, metaCalls, specVersion, ss58Format, tokenDecimals, tokenSymbol, types } = definition;
|
||||||
const registry = new TypeRegistry();
|
const registry = new TypeRegistry();
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
registry.register(types);
|
||||||
registry.register(types as any);
|
|
||||||
|
|
||||||
const isUnknown = genesisHash === '0x';
|
const isUnknown = genesisHash === '0x';
|
||||||
const metadata = metaCalls
|
const metadata = metaCalls
|
||||||
|
|||||||
@ -58,9 +58,8 @@ export function web3Enable (originName: string): Promise<InjectedExtension[]> {
|
|||||||
.map(([info, ext]): InjectedExtension => {
|
.map(([info, ext]): InjectedExtension => {
|
||||||
// if we don't have an accounts subscriber, add a single-shot version
|
// if we don't have an accounts subscriber, add a single-shot version
|
||||||
if (ext && !ext.accounts.subscribe) {
|
if (ext && !ext.accounts.subscribe) {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
ext.accounts.subscribe = (cb: (accounts: InjectedAccount[]) => void | Promise<void>): Unsubcall => {
|
||||||
ext.accounts.subscribe = (cb: (accounts: InjectedAccount[]) => any): Unsubcall => {
|
ext.accounts.get().then(cb).catch(console.error);
|
||||||
ext.accounts.get().then(cb).catch((error: Error) => console.error(error));
|
|
||||||
|
|
||||||
return (): void => {
|
return (): void => {
|
||||||
// no ubsubscribe needed, this is a single-shot
|
// no ubsubscribe needed, this is a single-shot
|
||||||
@ -119,25 +118,28 @@ export async function web3Accounts (): Promise<InjectedAccountWithMeta[]> {
|
|||||||
return accounts;
|
return accounts;
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
export async function web3AccountsSubscribe (cb: (accounts: InjectedAccountWithMeta[]) => void | Promise<void>): Promise<Unsubcall> {
|
||||||
export async function web3AccountsSubscribe (cb: (accounts: InjectedAccountWithMeta[]) => any): Promise<Unsubcall> {
|
|
||||||
if (!web3EnablePromise) {
|
if (!web3EnablePromise) {
|
||||||
return throwError('web3AccountsSubscribe');
|
return throwError('web3AccountsSubscribe');
|
||||||
}
|
}
|
||||||
|
|
||||||
const accounts: Record<string, InjectedAccount[]> = {};
|
const accounts: Record<string, InjectedAccount[]> = {};
|
||||||
|
|
||||||
const triggerUpdate = (): void => {
|
const triggerUpdate = (): void | Promise<void> => cb(
|
||||||
cb(Object.entries(accounts).reduce((result, [source, list]): InjectedAccountWithMeta[] => {
|
Object
|
||||||
result.push(...mapAccounts(source, list));
|
.entries(accounts)
|
||||||
|
.reduce((result: InjectedAccountWithMeta[], [source, list]): InjectedAccountWithMeta[] => {
|
||||||
|
result.push(...mapAccounts(source, list));
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}, [] as InjectedAccountWithMeta[]));
|
}, [])
|
||||||
};
|
);
|
||||||
|
|
||||||
const unsubs = (await web3EnablePromise).map(({ accounts: { subscribe }, name: source }): Unsubcall =>
|
const unsubs = (await web3EnablePromise).map(({ accounts: { subscribe }, name: source }): Unsubcall =>
|
||||||
subscribe((result): void => {
|
subscribe((result): void => {
|
||||||
accounts[source] = result;
|
accounts[source] = result;
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||||
triggerUpdate();
|
triggerUpdate();
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|||||||
@ -8,7 +8,7 @@
|
|||||||
"@babel/runtime": "^7.9.6"
|
"@babel/runtime": "^7.9.6"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/chrome": "^0.0.112",
|
"@types/chrome": "^0.0.114",
|
||||||
"@types/firefox-webext-browser": "^70.0.1"
|
"@types/firefox-webext-browser": "^70.0.1"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
|
|||||||
@ -27,8 +27,7 @@ export interface InjectedAccountWithMeta {
|
|||||||
|
|
||||||
export interface InjectedAccounts {
|
export interface InjectedAccounts {
|
||||||
get: () => Promise<InjectedAccount[]>;
|
get: () => Promise<InjectedAccount[]>;
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
subscribe: (cb: (accounts: InjectedAccount[]) => void | Promise<void>) => Unsubcall;
|
||||||
subscribe: (cb: (accounts: InjectedAccount[]) => any) => Unsubcall;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface InjectedExtensionInfo {
|
export interface InjectedExtensionInfo {
|
||||||
@ -56,7 +55,7 @@ export interface MetadataDef {
|
|||||||
ss58Format: number;
|
ss58Format: number;
|
||||||
tokenDecimals: number;
|
tokenDecimals: number;
|
||||||
tokenSymbol: string;
|
tokenSymbol: string;
|
||||||
types: Record<string, object | string>;
|
types: Record<string, Record<string, string> | string>;
|
||||||
metaCalls?: string;
|
metaCalls?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -9,8 +9,8 @@
|
|||||||
"@polkadot/extension-base": "0.26.0-beta.2",
|
"@polkadot/extension-base": "0.26.0-beta.2",
|
||||||
"@polkadot/extension-inject": "0.26.0-beta.2",
|
"@polkadot/extension-inject": "0.26.0-beta.2",
|
||||||
"@polkadot/keyring": "^2.10.1",
|
"@polkadot/keyring": "^2.10.1",
|
||||||
"@polkadot/react-identicon": "^0.53.1",
|
"@polkadot/react-identicon": "^0.54.0-beta.1",
|
||||||
"@polkadot/react-qr": "^0.53.1",
|
"@polkadot/react-qr": "^0.54.0-beta.1",
|
||||||
"@polkadot/util": "^2.10.1",
|
"@polkadot/util": "^2.10.1",
|
||||||
"@polkadot/util-crypto": "^2.10.1",
|
"@polkadot/util-crypto": "^2.10.1",
|
||||||
"react": "^16.13.1",
|
"react": "^16.13.1",
|
||||||
@ -28,7 +28,7 @@
|
|||||||
"@types/react-dom": "^16.9.8",
|
"@types/react-dom": "^16.9.8",
|
||||||
"@types/react-router": "^5.1.7",
|
"@types/react-router": "^5.1.7",
|
||||||
"@types/react-router-dom": "^5.1.5",
|
"@types/react-router-dom": "^5.1.5",
|
||||||
"@types/sinon-chrome": "^2.2.8",
|
"@types/sinon-chrome": "^2.2.9",
|
||||||
"@types/styled-components": "^5.1.0",
|
"@types/styled-components": "^5.1.0",
|
||||||
"enzyme": "^3.11.0",
|
"enzyme": "^3.11.0",
|
||||||
"enzyme-adapter-react-16": "^1.15.2",
|
"enzyme-adapter-react-16": "^1.15.2",
|
||||||
|
|||||||
@ -18,8 +18,8 @@ configure({ adapter: new Adapter() });
|
|||||||
describe('Account component', () => {
|
describe('Account component', () => {
|
||||||
let wrapper: ReactWrapper;
|
let wrapper: ReactWrapper;
|
||||||
const VALID_ADDRESS = 'HjoBp62cvsWDA3vtNMWxz6c9q13ReEHi9UGHK7JbZweH5g5';
|
const VALID_ADDRESS = 'HjoBp62cvsWDA3vtNMWxz6c9q13ReEHi9UGHK7JbZweH5g5';
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
||||||
const mountAccountComponent = (additionalAccountProperties: any, theme: Theme = themes.dark): ReactWrapper => mount(
|
const mountAccountComponent = (additionalAccountProperties: Record<string, unknown>, theme: Theme = themes.dark): ReactWrapper => mount(
|
||||||
<MemoryRouter>
|
<MemoryRouter>
|
||||||
<ThemeProvider theme={theme}>
|
<ThemeProvider theme={theme}>
|
||||||
<Account
|
<Account
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||||
|
|
||||||
import { AccountJson } from '@polkadot/extension-base/background/types';
|
import { AccountJson } from '@polkadot/extension-base/background/types';
|
||||||
|
import { ThemeProps } from '../../types';
|
||||||
|
|
||||||
import React, { useCallback, useContext, useState } from 'react';
|
import React, { useCallback, useContext, useState } from 'react';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
@ -82,7 +83,7 @@ function Account ({ address, className, isExternal, parentName }: Props): React.
|
|||||||
const MenuGroup = styled.div`
|
const MenuGroup = styled.div`
|
||||||
padding-bottom: 16px;
|
padding-bottom: 16px;
|
||||||
margin-bottom: 16px;
|
margin-bottom: 16px;
|
||||||
border-bottom: 1px solid ${({ theme }): string => theme.boxBorderColor};
|
border-bottom: 1px solid ${({ theme }: ThemeProps): string => theme.boxBorderColor};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const MenuItem = styled(Link)`
|
const MenuItem = styled(Link)`
|
||||||
|
|||||||
@ -2,6 +2,8 @@
|
|||||||
// This software may be modified and distributed under the terms
|
// This software may be modified and distributed under the terms
|
||||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||||
|
|
||||||
|
import { ThemeProps } from '../../types';
|
||||||
|
|
||||||
import React, { useContext } from 'react';
|
import React, { useContext } from 'react';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
|
|
||||||
@ -10,9 +12,7 @@ import { AddAccount, Header } from '../../partials';
|
|||||||
import AccountsTree from './AccountsTree';
|
import AccountsTree from './AccountsTree';
|
||||||
import qrIcon from '../../assets/qr.svg';
|
import qrIcon from '../../assets/qr.svg';
|
||||||
|
|
||||||
type Props = {};
|
export default function Accounts (): React.ReactElement {
|
||||||
|
|
||||||
export default function Accounts (): React.ReactElement<Props> {
|
|
||||||
const { hierarchy, master } = useContext(AccountContext);
|
const { hierarchy, master } = useContext(AccountContext);
|
||||||
const mediaAllowed = useContext(MediaContext);
|
const mediaAllowed = useContext(MediaContext);
|
||||||
|
|
||||||
@ -64,7 +64,7 @@ const QrButton = styled(Button)`
|
|||||||
${Svg} {
|
${Svg} {
|
||||||
width: 20px;
|
width: 20px;
|
||||||
height: 20px;
|
height: 20px;
|
||||||
background: ${({ theme }): string => theme.buttonTextColor};
|
background: ${({ theme }: ThemeProps): string => theme.buttonTextColor};
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|||||||
@ -19,6 +19,7 @@ import Request from './Request';
|
|||||||
configure({ adapter: new Adapter() });
|
configure({ adapter: new Adapter() });
|
||||||
|
|
||||||
describe('Authorize', () => {
|
describe('Authorize', () => {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
||||||
const mountAuthorize = (authorizeRequests: AuthorizeRequest[] = []): ReactWrapper => mount(
|
const mountAuthorize = (authorizeRequests: AuthorizeRequest[] = []): ReactWrapper => mount(
|
||||||
<AuthorizeReqContext.Provider value={authorizeRequests}>
|
<AuthorizeReqContext.Provider value={authorizeRequests}>
|
||||||
<ThemeProvider theme={themes.dark}>
|
<ThemeProvider theme={themes.dark}>
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||||
|
|
||||||
import { RequestAuthorizeTab } from '@polkadot/extension-base/background/types';
|
import { RequestAuthorizeTab } from '@polkadot/extension-base/background/types';
|
||||||
|
import { ThemeProps } from '../../types';
|
||||||
|
|
||||||
import React, { useContext } from 'react';
|
import React, { useContext } from 'react';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
@ -72,7 +73,7 @@ const RequestInfo = styled.div`
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin-bottom: 8px;
|
margin-bottom: 8px;
|
||||||
background: ${({ theme }): string => theme.highlightedAreaBackground};
|
background: ${({ theme }: ThemeProps): string => theme.highlightedAreaBackground};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const Info = styled.div`
|
const Info = styled.div`
|
||||||
@ -99,7 +100,7 @@ const RejectButton = styled(ActionBar)`
|
|||||||
export default styled(Request)`
|
export default styled(Request)`
|
||||||
|
|
||||||
.icon {
|
.icon {
|
||||||
background: ${({ theme }): string => theme.buttonBackgroundDanger};
|
background: ${({ theme }: ThemeProps): string => theme.buttonBackgroundDanger};
|
||||||
color: white;
|
color: white;
|
||||||
min-width: 18px;
|
min-width: 18px;
|
||||||
width: 14px;
|
width: 14px;
|
||||||
@ -118,7 +119,7 @@ export default styled(Request)`
|
|||||||
|
|
||||||
.tab-name,
|
.tab-name,
|
||||||
.tab-url {
|
.tab-url {
|
||||||
color: ${({ theme }): string => theme.textColor};
|
color: ${({ theme }: ThemeProps): string => theme.textColor};
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
max-width: 20rem;
|
max-width: 20rem;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|||||||
@ -9,7 +9,7 @@ import { AuthorizeReqContext } from '../../components';
|
|||||||
import { Header } from '../../partials';
|
import { Header } from '../../partials';
|
||||||
import Request from './Request';
|
import Request from './Request';
|
||||||
|
|
||||||
export default function Authorize (): React.ReactElement<{}> {
|
export default function Authorize (): React.ReactElement {
|
||||||
const requests = useContext(AuthorizeReqContext);
|
const requests = useContext(AuthorizeReqContext);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -3,7 +3,8 @@
|
|||||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||||
|
|
||||||
import React, { useCallback, useState } from 'react';
|
import React, { useCallback, useState } from 'react';
|
||||||
import { Address, BackButton, ButtonArea, NextStepButton, VerticalSpace } from '../..//components';
|
|
||||||
|
import { Address, BackButton, ButtonArea, NextStepButton, VerticalSpace } from '../../components';
|
||||||
import { Name, Password } from '../../partials';
|
import { Name, Password } from '../../partials';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
|
|||||||
@ -25,6 +25,7 @@ describe('Create Account', () => {
|
|||||||
address: 'HjoBp62cvsWDA3vtNMWxz6c9q13ReEHi9UGHK7JbZweH5g5',
|
address: 'HjoBp62cvsWDA3vtNMWxz6c9q13ReEHi9UGHK7JbZweH5g5',
|
||||||
seed: 'horse battery staple correct'
|
seed: 'horse battery staple correct'
|
||||||
};
|
};
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
||||||
const mountComponent = (): ReactWrapper => mount(
|
const mountComponent = (): ReactWrapper => mount(
|
||||||
<ActionContext.Provider value={onActionStub}>
|
<ActionContext.Provider value={onActionStub}>
|
||||||
<ThemeProvider theme={themes.dark}>
|
<ThemeProvider theme={themes.dark}>
|
||||||
|
|||||||
@ -2,9 +2,12 @@
|
|||||||
// This software may be modified and distributed under the terms
|
// This software may be modified and distributed under the terms
|
||||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||||
|
|
||||||
|
import { ThemeProps } from '../../types';
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import { ActionText, Title } from '@polkadot/extension-ui/components';
|
|
||||||
|
import { ActionText, Title } from '../../components';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
step: number;
|
step: number;
|
||||||
@ -36,16 +39,16 @@ const CreateAnAccount = styled(Title).attrs(() => ({
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
const CurrentStep = styled.span`
|
const CurrentStep = styled.span`
|
||||||
font-size: ${({ theme }): string => theme.labelFontSize};
|
font-size: ${({ theme }: ThemeProps): string => theme.labelFontSize};
|
||||||
line-height: ${({ theme }): string => theme.labelLineHeight};
|
line-height: ${({ theme }: ThemeProps): string => theme.labelLineHeight};
|
||||||
color: ${({ theme }): string => theme.primaryColor};
|
color: ${({ theme }: ThemeProps): string => theme.primaryColor};
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const TotalSteps = styled.span`
|
const TotalSteps = styled.span`
|
||||||
font-size: ${({ theme }): string => theme.labelFontSize};
|
font-size: ${({ theme }: ThemeProps): string => theme.labelFontSize};
|
||||||
line-height: ${({ theme }): string => theme.labelLineHeight};
|
line-height: ${({ theme }: ThemeProps): string => theme.labelLineHeight};
|
||||||
color: ${({ theme }): string => theme.textColor};
|
color: ${({ theme }: ThemeProps): string => theme.textColor};
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|||||||
@ -2,6 +2,8 @@
|
|||||||
// This software may be modified and distributed under the terms
|
// This software may be modified and distributed under the terms
|
||||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||||
|
|
||||||
|
import { ThemeProps } from '../../types';
|
||||||
|
|
||||||
import React, { useCallback, useRef, useState } from 'react';
|
import React, { useCallback, useRef, useState } from 'react';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
|
|
||||||
@ -54,11 +56,11 @@ const HiddenOptions = styled.div<{ visible: boolean }>`
|
|||||||
visibility: ${({ visible }): string => (visible ? 'visible' : 'hidden')};
|
visibility: ${({ visible }): string => (visible ? 'visible' : 'hidden')};
|
||||||
width: 430px;
|
width: 430px;
|
||||||
z-index: 100;
|
z-index: 100;
|
||||||
background: ${({ theme }): string => theme.bodyColor};
|
background: ${({ theme }: ThemeProps): string => theme.bodyColor};
|
||||||
max-height: ${({ visible }): string => (visible ? '200px' : '0')};
|
max-height: ${({ visible }): string => (visible ? '200px' : '0')};
|
||||||
overflow: scroll;
|
overflow: scroll;
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
border: 1px solid ${({ theme }): string => theme.boxBorderColor};
|
border: 1px solid ${({ theme }: ThemeProps): string => theme.boxBorderColor};
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
margin-top: -8px;
|
margin-top: -8px;
|
||||||
@ -81,10 +83,10 @@ export default styled(AddressDropdown)`
|
|||||||
width: 30px;
|
width: 30px;
|
||||||
height: 30px;
|
height: 30px;
|
||||||
background: url(${arrow}) center no-repeat;
|
background: url(${arrow}) center no-repeat;
|
||||||
background-color: ${({ theme }): string => theme.inputBackground};
|
background-color: ${({ theme }: ThemeProps): string => theme.inputBackground};
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
border: 1px solid ${({ theme }): string => theme.boxBorderColor};
|
border: 1px solid ${({ theme }: ThemeProps): string => theme.boxBorderColor};
|
||||||
}
|
}
|
||||||
|
|
||||||
${Address} ${Svg} {
|
${Address} ${Svg} {
|
||||||
|
|||||||
@ -30,6 +30,7 @@ describe('Export component', () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
jest.spyOn(messaging, 'exportAccount').mockResolvedValue({ exportedJson: '{ "meta": { "name": "account_name" } }' });
|
jest.spyOn(messaging, 'exportAccount').mockResolvedValue({ exportedJson: '{ "meta": { "name": "account_name" } }' });
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||||
wrapper = mount(
|
wrapper = mount(
|
||||||
<MemoryRouter initialEntries={ [`/account/export/${VALID_ADDRESS}`] }>
|
<MemoryRouter initialEntries={ [`/account/export/${VALID_ADDRESS}`] }>
|
||||||
<ThemeProvider theme={themes.dark}>
|
<ThemeProvider theme={themes.dark}>
|
||||||
|
|||||||
@ -29,9 +29,10 @@ function Export ({ match: { params: { address } } }: Props): React.ReactElement<
|
|||||||
exportAccount(address, pass)
|
exportAccount(address, pass)
|
||||||
.then(({ exportedJson }) => {
|
.then(({ exportedJson }) => {
|
||||||
const element = document.createElement('a');
|
const element = document.createElement('a');
|
||||||
|
const { meta } = JSON.parse(exportedJson) as { meta: { name: string } };
|
||||||
|
|
||||||
element.href = `data:text/plain;charset=utf-8,${exportedJson}`;
|
element.href = `data:text/plain;charset=utf-8,${exportedJson}`;
|
||||||
element.download = `${JSON.parse(exportedJson).meta.name}_exported_account_${Date.now()}.json`;
|
element.download = `${meta.name}_exported_account_${Date.now()}.json`;
|
||||||
element.click();
|
element.click();
|
||||||
|
|
||||||
onAction('/');
|
onAction('/');
|
||||||
|
|||||||
@ -9,9 +9,7 @@ import { ActionContext, Address, NextStepButton, ButtonArea, VerticalSpace } fro
|
|||||||
import { createAccountExternal } from '../messaging';
|
import { createAccountExternal } from '../messaging';
|
||||||
import { Header, Name } from '../partials';
|
import { Header, Name } from '../partials';
|
||||||
|
|
||||||
type Props = {};
|
export default function ImportQr (): React.ReactElement {
|
||||||
|
|
||||||
export default function ImportQr (): React.ReactElement<Props> {
|
|
||||||
const onAction = useContext(ActionContext);
|
const onAction = useContext(ActionContext);
|
||||||
const [account, setAccount] = useState<null | { address: string; genesisHash: string }>(null);
|
const [account, setAccount] = useState<null | { address: string; genesisHash: string }>(null);
|
||||||
const [name, setName] = useState<string | null>(null);
|
const [name, setName] = useState<string | null>(null);
|
||||||
|
|||||||
@ -10,24 +10,22 @@ import { allOf, isNotShorterThan, Result } from '../validators';
|
|||||||
import { createAccountSuri, validateSeed } from '../messaging';
|
import { createAccountSuri, validateSeed } from '../messaging';
|
||||||
import { Header, Name, Password } from '../partials';
|
import { Header, Name, Password } from '../partials';
|
||||||
|
|
||||||
type Props = {};
|
async function validate (suri: string): Promise<Result<string>> {
|
||||||
|
|
||||||
const validate = async (suri: string): Promise<Result<string>> => {
|
|
||||||
try {
|
try {
|
||||||
await validateSeed(suri);
|
await validateSeed(suri);
|
||||||
|
|
||||||
return Result.ok(suri);
|
return Result.ok(suri);
|
||||||
} catch (err) {
|
} catch (error) {
|
||||||
return Result.error(err.message);
|
return Result.error((error as Error).message);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
const isSeedValid = allOf(
|
const isSeedValid = allOf(
|
||||||
isNotShorterThan(1, 'Seed is empty'),
|
isNotShorterThan(1, 'Seed is empty'),
|
||||||
validate
|
validate
|
||||||
);
|
);
|
||||||
|
|
||||||
export default function Import (): React.ReactElement<Props> {
|
export default function Import (): React.ReactElement {
|
||||||
const onAction = useContext(ActionContext);
|
const onAction = useContext(ActionContext);
|
||||||
const [account, setAccount] = useState<null | { address: string; suri: string }>(null);
|
const [account, setAccount] = useState<null | { address: string; suri: string }>(null);
|
||||||
const [name, setName] = useState<string | null>(null);
|
const [name, setName] = useState<string | null>(null);
|
||||||
@ -49,8 +47,8 @@ export default function Import (): React.ReactElement<Props> {
|
|||||||
// this should always be the case
|
// this should always be the case
|
||||||
if (name && password && account) {
|
if (name && password && account) {
|
||||||
createAccountSuri(name, password, account.suri)
|
createAccountSuri(name, password, account.suri)
|
||||||
.then((): void => onAction('/'))
|
.then(() => onAction('/'))
|
||||||
.catch((error: Error) => console.error(error));
|
.catch(console.error);
|
||||||
}
|
}
|
||||||
}, [account, name, onAction, password]);
|
}, [account, name, onAction, password]);
|
||||||
|
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||||
|
|
||||||
import { MetadataDef } from '@polkadot/extension-inject/types';
|
import { MetadataDef } from '@polkadot/extension-inject/types';
|
||||||
|
import { ThemeProps } from '../../types';
|
||||||
|
|
||||||
import React, { useContext } from 'react';
|
import React, { useContext } from 'react';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
@ -10,6 +11,7 @@ import styled from 'styled-components';
|
|||||||
import { ActionBar, ActionContext, Button, Link, Table, Warning } from '../../components';
|
import { ActionBar, ActionContext, Button, Link, Table, Warning } from '../../components';
|
||||||
import useMetadata from '../../hooks/useMetadata';
|
import useMetadata from '../../hooks/useMetadata';
|
||||||
import { approveMetaRequest, rejectMetaRequest } from '../../messaging';
|
import { approveMetaRequest, rejectMetaRequest } from '../../messaging';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
className?: string;
|
className?: string;
|
||||||
request: MetadataDef;
|
request: MetadataDef;
|
||||||
@ -78,7 +80,7 @@ const RequestInfo = styled.div`
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin-bottom: 8px;
|
margin-bottom: 8px;
|
||||||
background: ${({ theme }): string => theme.highlightedAreaBackground};
|
background: ${({ theme }: ThemeProps): string => theme.highlightedAreaBackground};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const AcceptButton = styled(Button)`
|
const AcceptButton = styled(Button)`
|
||||||
@ -99,7 +101,7 @@ const RejectButton = styled(ActionBar)`
|
|||||||
|
|
||||||
export default styled(Request)`
|
export default styled(Request)`
|
||||||
.icon {
|
.icon {
|
||||||
background: ${({ theme }): string => theme.buttonBackgroundDanger};
|
background: ${({ theme }: ThemeProps): string => theme.buttonBackgroundDanger};
|
||||||
color: white;
|
color: white;
|
||||||
min-width: 18px;
|
min-width: 18px;
|
||||||
width: 14px;
|
width: 14px;
|
||||||
@ -118,7 +120,7 @@ export default styled(Request)`
|
|||||||
|
|
||||||
.tab-name,
|
.tab-name,
|
||||||
.tab-url {
|
.tab-url {
|
||||||
color: ${({ theme }): string => theme.textColor};
|
color: ${({ theme }: ThemeProps): string => theme.textColor};
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
max-width: 20rem;
|
max-width: 20rem;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|||||||
@ -8,7 +8,7 @@ import { Loading, MetadataReqContext } from '../../components';
|
|||||||
import { Header } from '../../partials';
|
import { Header } from '../../partials';
|
||||||
import Request from './Request';
|
import Request from './Request';
|
||||||
|
|
||||||
export default function Metadata (): React.ReactElement<{}> {
|
export default function Metadata (): React.ReactElement {
|
||||||
const requests = useContext(MetadataReqContext);
|
const requests = useContext(MetadataReqContext);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -33,8 +33,7 @@ function decodeMethod (data: string, isDecoded: boolean, chain: Chain | null, sp
|
|||||||
try {
|
try {
|
||||||
if (isDecoded && chain && chain.hasMetadata && specVersion.eqn(chain.specVersion)) {
|
if (isDecoded && chain && chain.hasMetadata && specVersion.eqn(chain.specVersion)) {
|
||||||
method = chain.registry.createType('Call', data);
|
method = chain.registry.createType('Call', data);
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
args = (method.toHuman() as { args: AnyJson }).args;
|
||||||
args = (method.toHuman() as any).args;
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
args = null;
|
args = null;
|
||||||
|
|||||||
@ -43,6 +43,7 @@ describe.skip('Signing requests', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const mountComponent = async (): Promise<void> => {
|
const mountComponent = async (): Promise<void> => {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||||
wrapper = mount(
|
wrapper = mount(
|
||||||
<ActionContext.Provider value={onActionStub}>
|
<ActionContext.Provider value={onActionStub}>
|
||||||
<ThemeProvider theme={themes.dark}>
|
<ThemeProvider theme={themes.dark}>
|
||||||
|
|||||||
@ -2,8 +2,11 @@
|
|||||||
// This software may be modified and distributed under the terms
|
// This software may be modified and distributed under the terms
|
||||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||||
|
|
||||||
|
import { ThemeProps } from '../../types';
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
|
|
||||||
import { Svg } from '../../components';
|
import { Svg } from '../../components';
|
||||||
import ArrowLeftImage from '../../assets/arrowLeft.svg';
|
import ArrowLeftImage from '../../assets/arrowLeft.svg';
|
||||||
|
|
||||||
@ -15,6 +18,10 @@ interface Props {
|
|||||||
className?: string;
|
className?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface ArrowProps extends ThemeProps {
|
||||||
|
isActive: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
function TransactionIndex ({ index, onNextClick, onPreviousClick, totalItems }: Props): React.ReactElement<Props> {
|
function TransactionIndex ({ index, onNextClick, onPreviousClick, totalItems }: Props): React.ReactElement<Props> {
|
||||||
const previousClickActive = index !== 0;
|
const previousClickActive = index !== 0;
|
||||||
const nextClickActive = index < totalItems - 1;
|
const nextClickActive = index < totalItems - 1;
|
||||||
@ -48,29 +55,23 @@ const CreationSteps = styled.div`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
const CurrentStep = styled.span`
|
const CurrentStep = styled.span`
|
||||||
font-size: ${({ theme }): string => theme.labelFontSize};
|
font-size: ${({ theme }: ThemeProps): string => theme.labelFontSize};
|
||||||
line-height: ${({ theme }): string => theme.labelLineHeight};
|
line-height: ${({ theme }: ThemeProps): string => theme.labelLineHeight};
|
||||||
color: ${({ theme }): string => theme.primaryColor};
|
color: ${({ theme }: ThemeProps): string => theme.primaryColor};
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const TotalSteps = styled.span`
|
const TotalSteps = styled.span`
|
||||||
font-size: ${({ theme }): string => theme.labelFontSize};
|
font-size: ${({ theme }: ThemeProps): string => theme.labelFontSize};
|
||||||
line-height: ${({ theme }): string => theme.labelLineHeight};
|
line-height: ${({ theme }: ThemeProps): string => theme.labelLineHeight};
|
||||||
color: ${({ theme }): string => theme.textColor};
|
color: ${({ theme }: ThemeProps): string => theme.textColor};
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
interface ArrowProps {
|
const ArrowLeft = styled(Svg).attrs(() => ({ src: ArrowLeftImage }))<ArrowProps>`
|
||||||
isActive: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
const ArrowLeft = styled(Svg).attrs(() => ({
|
|
||||||
src: ArrowLeftImage
|
|
||||||
}))<ArrowProps>`
|
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
background: ${({ isActive, theme }): string => isActive ? theme.primaryColor : theme.iconNeutralColor};
|
background: ${({ isActive, theme }: ArrowProps): string => isActive ? theme.primaryColor : theme.iconNeutralColor};
|
||||||
cursor: ${({ isActive }): string => isActive ? 'pointer' : 'default'};
|
cursor: ${({ isActive }): string => isActive ? 'pointer' : 'default'};
|
||||||
width: 12px;
|
width: 12px;
|
||||||
height: 12px;
|
height: 12px;
|
||||||
|
|||||||
@ -25,7 +25,7 @@ export default function Unlock ({ buttonText = 'Sign the transaction', className
|
|||||||
);
|
);
|
||||||
const _onClick = useCallback(
|
const _onClick = useCallback(
|
||||||
(): Promise<void> =>
|
(): Promise<void> =>
|
||||||
onSign(password).catch((error): void => setError(error.message)),
|
onSign(password).catch((error: Error) => setError(error.message)),
|
||||||
[onSign, password]
|
[onSign, password]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@ -15,7 +15,7 @@ function isInnerTransaction (signingRequest: SigningRequest): boolean {
|
|||||||
return 'blockNumber' in signingRequest.request.payload;
|
return 'blockNumber' in signingRequest.request.payload;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Signing (): React.ReactElement<{}> {
|
export default function Signing (): React.ReactElement {
|
||||||
const requests = useContext(SigningReqContext);
|
const requests = useContext(SigningReqContext);
|
||||||
const [requestIndex, setRequestIndex] = useState(0);
|
const [requestIndex, setRequestIndex] = useState(0);
|
||||||
const isTransaction = useMemo(
|
const isTransaction = useMemo(
|
||||||
|
|||||||
@ -2,14 +2,14 @@
|
|||||||
// This software may be modified and distributed under the terms
|
// This software may be modified and distributed under the terms
|
||||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||||
|
|
||||||
|
import { ThemeProps as Props } from '../types';
|
||||||
|
|
||||||
import React, { useContext } from 'react';
|
import React, { useContext } from 'react';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
|
|
||||||
import { ActionContext, Box, Button, ButtonArea, List, VerticalSpace } from '../components';
|
import { ActionContext, Box, Button, ButtonArea, List, VerticalSpace } from '../components';
|
||||||
import { Header } from '../partials';
|
import { Header } from '../partials';
|
||||||
|
|
||||||
type Props = {};
|
|
||||||
|
|
||||||
export default function Welcome (): React.ReactElement<Props> {
|
export default function Welcome (): React.ReactElement<Props> {
|
||||||
const onAction = useContext(ActionContext);
|
const onAction = useContext(ActionContext);
|
||||||
|
|
||||||
@ -41,11 +41,11 @@ export default function Welcome (): React.ReactElement<Props> {
|
|||||||
const Note = styled.p`
|
const Note = styled.p`
|
||||||
margin-bottom: 6px;
|
margin-bottom: 6px;
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
color: ${({ theme }): string => theme.subTextColor};
|
color: ${({ theme }: Props): string => theme.subTextColor};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const TextBox = styled(Box)`
|
const TextBox = styled(Box)`
|
||||||
margin: 0.75rem 24px;
|
margin: 0.75rem 24px;
|
||||||
border: 1px solid ${({ theme }): string => theme.inputBorderColor};
|
border: 1px solid ${({ theme }: Props): string => theme.inputBorderColor};
|
||||||
color: ${({ theme }): string => theme.subTextColor};
|
color: ${({ theme }: Props): string => theme.subTextColor};
|
||||||
`;
|
`;
|
||||||
|
|||||||
@ -44,7 +44,7 @@ async function requestMediaAccess (cameraOn: boolean): Promise<boolean> {
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Permission for video declined', error.message);
|
console.error('Permission for video declined', (error as Error).message);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@ -62,7 +62,7 @@ function initAccountContext (accounts: AccountJson[]): AccountsContext {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Popup (): React.ReactElement<{}> {
|
export default function Popup (): React.ReactElement {
|
||||||
const [accounts, setAccounts] = useState<null | AccountJson[]>(null);
|
const [accounts, setAccounts] = useState<null | AccountJson[]>(null);
|
||||||
const [authRequests, setAuthRequests] = useState<null | AuthorizeRequest[]>(null);
|
const [authRequests, setAuthRequests] = useState<null | AuthorizeRequest[]>(null);
|
||||||
const [cameraOn, setCameraOn] = useState(settings.get().camera === 'on');
|
const [cameraOn, setCameraOn] = useState(settings.get().camera === 'on');
|
||||||
@ -93,7 +93,7 @@ export default function Popup (): React.ReactElement<{}> {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect((): void => {
|
useEffect((): void => {
|
||||||
requestMediaAccess(cameraOn).then(setMediaAllowed);
|
requestMediaAccess(cameraOn).then(setMediaAllowed).catch(console.error);
|
||||||
}, [cameraOn]);
|
}, [cameraOn]);
|
||||||
|
|
||||||
const Root = isWelcomeDone
|
const Root = isWelcomeDone
|
||||||
|
|||||||
@ -2,6 +2,8 @@
|
|||||||
// This software may be modified and distributed under the terms
|
// This software may be modified and distributed under the terms
|
||||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||||
|
|
||||||
|
import { ThemeProps } from '../types';
|
||||||
|
|
||||||
import React, { MouseEventHandler } from 'react';
|
import React, { MouseEventHandler } from 'react';
|
||||||
import Svg from '@polkadot/extension-ui/components/Svg';
|
import Svg from '@polkadot/extension-ui/components/Svg';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
@ -29,14 +31,14 @@ export default styled(ActionText)`
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
span {
|
span {
|
||||||
font-size: ${({ theme }): string => theme.labelFontSize};
|
font-size: ${({ theme }: ThemeProps): string => theme.labelFontSize};
|
||||||
line-height: ${({ theme }): string => theme.labelLineHeight};
|
line-height: ${({ theme }: ThemeProps): string => theme.labelLineHeight};
|
||||||
text-decoration-line: underline;
|
text-decoration-line: underline;
|
||||||
color: ${({ theme }): string => theme.labelColor}
|
color: ${({ theme }: ThemeProps): string => theme.labelColor}
|
||||||
}
|
}
|
||||||
|
|
||||||
${Svg} {
|
${Svg} {
|
||||||
background: ${({ theme }): string => theme.iconNeutralColor};
|
background: ${({ theme }: ThemeProps): string => theme.iconNeutralColor};
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
position: relative;
|
position: relative;
|
||||||
top: 2px;
|
top: 2px;
|
||||||
|
|||||||
@ -2,6 +2,8 @@
|
|||||||
// This software may be modified and distributed under the terms
|
// This software may be modified and distributed under the terms
|
||||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||||
|
|
||||||
|
import { ThemeProps } from '../types';
|
||||||
|
|
||||||
import { AccountJson, AccountWithChildren } from '@polkadot/extension-base/background/types';
|
import { AccountJson, AccountWithChildren } from '@polkadot/extension-base/background/types';
|
||||||
import { Chain } from '@polkadot/extension-chains/types';
|
import { Chain } from '@polkadot/extension-chains/types';
|
||||||
|
|
||||||
@ -168,9 +170,9 @@ const CopyAddress = styled.div`
|
|||||||
width: 14px;
|
width: 14px;
|
||||||
height: 14px;
|
height: 14px;
|
||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
background: ${({ theme }): string => theme.accountDotsIconColor};
|
background: ${({ theme }: ThemeProps): string => theme.accountDotsIconColor};
|
||||||
&:hover {
|
&:hover {
|
||||||
background: ${({ theme }): string => theme.labelColor};
|
background: ${({ theme }: ThemeProps): string => theme.labelColor};
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -207,7 +209,7 @@ const FullAddress = styled.div`
|
|||||||
width: 270px;
|
width: 270px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
color: ${({ theme }): string => theme.labelColor};
|
color: ${({ theme }: ThemeProps): string => theme.labelColor};
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
line-height: 16px;
|
line-height: 16px;
|
||||||
`;
|
`;
|
||||||
@ -234,12 +236,12 @@ const Settings = styled.div`
|
|||||||
top: 25%;
|
top: 25%;
|
||||||
bottom: 25%;
|
bottom: 25%;
|
||||||
width: 1px;
|
width: 1px;
|
||||||
background: ${({ theme }): string => theme.boxBorderColor};
|
background: ${({ theme }: ThemeProps): string => theme.boxBorderColor};
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
background: ${({ theme }): string => theme.readonlyInputBackground};
|
background: ${({ theme }: ThemeProps): string => theme.readonlyInputBackground};
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@ -248,13 +250,13 @@ Settings.displayName = 'Details';
|
|||||||
const ActionsIcon = styled(Svg).attrs(() => ({
|
const ActionsIcon = styled(Svg).attrs(() => ({
|
||||||
src: details
|
src: details
|
||||||
}))`
|
}))`
|
||||||
background: ${({ theme }): string => theme.accountDotsIconColor};
|
background: ${({ theme }: ThemeProps): string => theme.accountDotsIconColor};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const ActiveActionsIcon = styled(Svg).attrs(() => ({
|
const ActiveActionsIcon = styled(Svg).attrs(() => ({
|
||||||
src: details
|
src: details
|
||||||
}))`
|
}))`
|
||||||
background: ${({ theme }): string => theme.primaryColor};
|
background: ${({ theme }: ThemeProps): string => theme.primaryColor};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const Banner = styled.div`
|
const Banner = styled.div`
|
||||||
@ -269,7 +271,7 @@ const Banner = styled.div`
|
|||||||
const ChainBanner = styled(Banner)`
|
const ChainBanner = styled(Banner)`
|
||||||
padding: 0.1rem 0.5rem;
|
padding: 0.1rem 0.5rem;
|
||||||
right: 40px;
|
right: 40px;
|
||||||
background: ${({ theme }): string => theme.primaryColor};
|
background: ${({ theme }: ThemeProps): string => theme.primaryColor};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const ParentName = styled.div`
|
const ParentName = styled.div`
|
||||||
@ -277,7 +279,7 @@ const ParentName = styled.div`
|
|||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
font-size: 10px;
|
font-size: 10px;
|
||||||
line-height: 14px;
|
line-height: 14px;
|
||||||
color: ${({ theme }): string => theme.labelColor};
|
color: ${({ theme }: ThemeProps): string => theme.labelColor};
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
width: 270px;
|
width: 270px;
|
||||||
@ -290,7 +292,7 @@ const ArrowLabel = styled(Svg).attrs(() => ({
|
|||||||
top: 5px;
|
top: 5px;
|
||||||
width: 9px;
|
width: 9px;
|
||||||
height: 9px;
|
height: 9px;
|
||||||
background: ${({ theme }): string => theme.labelColor};
|
background: ${({ theme }: ThemeProps): string => theme.labelColor};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const MovableMenu = styled(Menu) <{ isMoved: boolean }>`
|
const MovableMenu = styled(Menu) <{ isMoved: boolean }>`
|
||||||
@ -302,8 +304,8 @@ export default styled(Address)`
|
|||||||
margin-bottom: 8px;
|
margin-bottom: 8px;
|
||||||
|
|
||||||
& > div {
|
& > div {
|
||||||
background: ${({ theme }): string => theme.accountBackground};
|
background: ${({ theme }: ThemeProps): string => theme.accountBackground};
|
||||||
border: 1px solid ${({ theme }): string => theme.boxBorderColor};
|
border: 1px solid ${({ theme }: ThemeProps): string => theme.boxBorderColor};
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,8 @@
|
|||||||
// This software may be modified and distributed under the terms
|
// This software may be modified and distributed under the terms
|
||||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||||
|
|
||||||
|
import { ThemeProps } from '../types';
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
|
|
||||||
@ -24,7 +26,7 @@ export default function BackButton ({ onClick }: Props): React.ReactElement<Prop
|
|||||||
const SmallButton = styled(Button)`
|
const SmallButton = styled(Button)`
|
||||||
margin-right: 11px;
|
margin-right: 11px;
|
||||||
width: 42px;
|
width: 42px;
|
||||||
background: ${({ theme }): string => theme.backButtonBackground};
|
background: ${({ theme }: ThemeProps): string => theme.backButtonBackground};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const ArrowLeft = styled(Svg).attrs(() => ({
|
const ArrowLeft = styled(Svg).attrs(() => ({
|
||||||
@ -34,5 +36,5 @@ const ArrowLeft = styled(Svg).attrs(() => ({
|
|||||||
height: 12px;
|
height: 12px;
|
||||||
display: block;
|
display: block;
|
||||||
margin: auto;
|
margin: auto;
|
||||||
background: ${({ theme }): string => theme.backButtonTextColor};
|
background: ${({ theme }: ThemeProps): string => theme.backButtonTextColor};
|
||||||
`;
|
`;
|
||||||
|
|||||||
@ -2,6 +2,8 @@
|
|||||||
// This software may be modified and distributed under the terms
|
// This software may be modified and distributed under the terms
|
||||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||||
|
|
||||||
|
import { ThemeProps } from '../types';
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
|
|
||||||
@ -21,19 +23,19 @@ function Box ({ banner, children, className }: Props): React.ReactElement<Props>
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default styled(Box)`
|
export default styled(Box)`
|
||||||
background: ${({ theme }): string => theme.readonlyInputBackground};
|
background: ${({ theme }: ThemeProps): string => theme.readonlyInputBackground};
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: ${({ theme }): string => theme.borderRadius};
|
border-radius: ${({ theme }: ThemeProps): string => theme.borderRadius};
|
||||||
color: ${({ theme }): string => theme.textColor};
|
color: ${({ theme }: ThemeProps): string => theme.textColor};
|
||||||
font-family: ${({ theme }): string => theme.fontFamily};
|
font-family: ${({ theme }: ThemeProps): string => theme.fontFamily};
|
||||||
font-size: ${({ theme }): string => theme.fontSize};
|
font-size: ${({ theme }: ThemeProps): string => theme.fontSize};
|
||||||
margin: ${({ theme }): string => theme.boxMargin};
|
margin: ${({ theme }: ThemeProps): string => theme.boxMargin};
|
||||||
padding: ${({ theme }): string => theme.boxPadding};
|
padding: ${({ theme }: ThemeProps): string => theme.boxPadding};
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
.banner {
|
.banner {
|
||||||
background: darkorange;
|
background: darkorange;
|
||||||
border-radius: 0 ${({ theme }): string => theme.borderRadius} 0 ${({ theme }): string => theme.borderRadius};
|
border-radius: 0 ${({ theme }: ThemeProps): string => theme.borderRadius} 0 ${({ theme }: ThemeProps): string => theme.borderRadius};
|
||||||
color: white;
|
color: white;
|
||||||
font-size: 0.75rem;
|
font-size: 0.75rem;
|
||||||
padding: 0.25rem 0.5rem;
|
padding: 0.25rem 0.5rem;
|
||||||
|
|||||||
@ -2,10 +2,12 @@
|
|||||||
// This software may be modified and distributed under the terms
|
// This software may be modified and distributed under the terms
|
||||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||||
|
|
||||||
|
import { ThemeProps } from '../types';
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
|
|
||||||
interface Props {
|
interface Props extends ThemeProps {
|
||||||
className?: string;
|
className?: string;
|
||||||
children?: React.ReactNode;
|
children?: React.ReactNode;
|
||||||
isDanger?: boolean;
|
isDanger?: boolean;
|
||||||
@ -41,17 +43,17 @@ function Button ({ children, className, isDisabled, onClick, to }: Props): React
|
|||||||
export default styled(Button)`
|
export default styled(Button)`
|
||||||
display: block;
|
display: block;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: ${({ isDanger }): string => isDanger ? '40px' : '48px'};
|
height: ${({ isDanger }: Props): string => isDanger ? '40px' : '48px'};
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: ${({ theme }): string => theme.borderRadius};
|
border-radius: ${({ theme }: Props): string => theme.borderRadius};
|
||||||
color: ${({ theme }): string => theme.buttonTextColor};
|
color: ${({ theme }: Props): string => theme.buttonTextColor};
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
font-weight: 800;
|
font-weight: 800;
|
||||||
line-height: 20px;
|
line-height: 20px;
|
||||||
padding: 0 1rem;
|
padding: 0 1rem;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
background: ${({ isDanger, theme }): string => isDanger ? theme.buttonBackgroundDanger : theme.buttonBackground};
|
background: ${({ isDanger, theme }: Props): string => isDanger ? theme.buttonBackgroundDanger : theme.buttonBackground};
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
&:disabled {
|
&:disabled {
|
||||||
@ -60,6 +62,6 @@ export default styled(Button)`
|
|||||||
}
|
}
|
||||||
|
|
||||||
&:not(:disabled):hover {
|
&:not(:disabled):hover {
|
||||||
background: ${({ isDanger, theme }): string => isDanger ? theme.buttonBackgroundDangerHover : theme.buttonBackgroundHover};
|
background: ${({ isDanger, theme }: Props): string => isDanger ? theme.buttonBackgroundDangerHover : theme.buttonBackgroundHover};
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|||||||
@ -2,14 +2,16 @@
|
|||||||
// This software may be modified and distributed under the terms
|
// This software may be modified and distributed under the terms
|
||||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||||
|
|
||||||
|
import { ThemeProps } from '../types';
|
||||||
|
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import Button from './Button';
|
import Button from './Button';
|
||||||
|
|
||||||
export default styled.div`
|
export default styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
background: ${({ theme }): string => theme.highlightedAreaBackground};
|
background: ${({ theme }: ThemeProps): string => theme.highlightedAreaBackground};
|
||||||
border-top: 1px solid ${({ theme }): string => theme.inputBorderColor};
|
border-top: 1px solid ${({ theme }: ThemeProps): string => theme.inputBorderColor};
|
||||||
padding: 12px 24px;
|
padding: 12px 24px;
|
||||||
|
|
||||||
&&& {
|
&&& {
|
||||||
|
|||||||
@ -2,6 +2,8 @@
|
|||||||
// This software may be modified and distributed under the terms
|
// This software may be modified and distributed under the terms
|
||||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||||
|
|
||||||
|
import { ThemeProps } from '../types';
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import Checkmark from '../assets/checkmark.svg';
|
import Checkmark from '../assets/checkmark.svg';
|
||||||
@ -30,7 +32,7 @@ function Checkbox ({ checked, className, label, onChange }: Props): React.ReactE
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default styled(Checkbox)`
|
export default styled(Checkbox)`
|
||||||
margin: ${({ theme }): string => theme.boxMargin};
|
margin: ${({ theme }: ThemeProps): string => theme.boxMargin};
|
||||||
|
|
||||||
label {
|
label {
|
||||||
display: block;
|
display: block;
|
||||||
@ -39,9 +41,9 @@ export default styled(Checkbox)`
|
|||||||
user-select: none;
|
user-select: none;
|
||||||
padding-left: 24px;
|
padding-left: 24px;
|
||||||
padding-top: 1px;
|
padding-top: 1px;
|
||||||
color: ${({ theme }): string => theme.subTextColor};
|
color: ${({ theme }: ThemeProps): string => theme.subTextColor};
|
||||||
font-size: ${({ theme }): string => theme.fontSize};
|
font-size: ${({ theme }: ThemeProps): string => theme.fontSize};
|
||||||
line-height: ${({ theme }): string => theme.lineHeight};
|
line-height: ${({ theme }: ThemeProps): string => theme.lineHeight};
|
||||||
|
|
||||||
& input {
|
& input {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@ -57,10 +59,10 @@ export default styled(Checkbox)`
|
|||||||
left: 0;
|
left: 0;
|
||||||
height: 16px;
|
height: 16px;
|
||||||
width: 16px;
|
width: 16px;
|
||||||
border-radius: ${({ theme }): string => theme.borderRadius};
|
border-radius: ${({ theme }: ThemeProps): string => theme.borderRadius};
|
||||||
background-color: ${({ theme }): string => theme.readonlyInputBackground};
|
background-color: ${({ theme }: ThemeProps): string => theme.readonlyInputBackground};
|
||||||
border: 1px solid ${({ theme }): string => theme.inputBorderColor};
|
border: 1px solid ${({ theme }: ThemeProps): string => theme.inputBorderColor};
|
||||||
border: 1px solid ${({ theme }): string => theme.inputBorderColor};
|
border: 1px solid ${({ theme }: ThemeProps): string => theme.inputBorderColor};
|
||||||
&:after {
|
&:after {
|
||||||
content: '';
|
content: '';
|
||||||
display: none;
|
display: none;
|
||||||
@ -71,12 +73,12 @@ export default styled(Checkbox)`
|
|||||||
top: 2px;
|
top: 2px;
|
||||||
mask: url(${Checkmark});
|
mask: url(${Checkmark});
|
||||||
mask-size: cover;
|
mask-size: cover;
|
||||||
background: ${({ theme }): string => theme.primaryColor};
|
background: ${({ theme }: ThemeProps): string => theme.primaryColor};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover input ~ span {
|
&:hover input ~ span {
|
||||||
background-color: ${({ theme }): string => theme.inputBackground};
|
background-color: ${({ theme }: ThemeProps): string => theme.inputBackground};
|
||||||
}
|
}
|
||||||
|
|
||||||
input:checked ~ span:after {
|
input:checked ~ span:after {
|
||||||
|
|||||||
@ -2,6 +2,8 @@
|
|||||||
// This software may be modified and distributed under the terms
|
// This software may be modified and distributed under the terms
|
||||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||||
|
|
||||||
|
import { ThemeProps } from '../types';
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
|
|
||||||
@ -13,7 +15,7 @@ interface DropdownOption {
|
|||||||
value: string;
|
value: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Props {
|
interface Props extends ThemeProps {
|
||||||
className?: string;
|
className?: string;
|
||||||
defaultValue?: string | null;
|
defaultValue?: string | null;
|
||||||
isError?: boolean;
|
isError?: boolean;
|
||||||
@ -64,16 +66,16 @@ export default styled(Dropdown)`
|
|||||||
-webkit-appearance: none;
|
-webkit-appearance: none;
|
||||||
-moz-appearance: none;
|
-moz-appearance: none;
|
||||||
appearance: none;
|
appearance: none;
|
||||||
background: ${({ theme }): string => theme.readonlyInputBackground};
|
background: ${({ theme }: Props): string => theme.readonlyInputBackground};
|
||||||
border-color: ${({ isError, theme }): string => isError ? theme.errorBorderColor : theme.inputBorderColor};
|
border-color: ${({ isError, theme }: Props): string => isError ? theme.errorBorderColor : theme.inputBorderColor};
|
||||||
border-radius: ${({ theme }): string => theme.borderRadius};
|
border-radius: ${({ theme }: ThemeProps): string => theme.borderRadius};
|
||||||
border-style: solid;
|
border-style: solid;
|
||||||
border-width: 1px;
|
border-width: 1px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
color: ${({ isError, theme }): string => isError ? theme.errorBorderColor : theme.textColor};
|
color: ${({ isError, theme }: Props): string => isError ? theme.errorBorderColor : theme.textColor};
|
||||||
display: block;
|
display: block;
|
||||||
font-family: ${({ theme }): string => theme.fontFamily};
|
font-family: ${({ theme }: Props): string => theme.fontFamily};
|
||||||
font-size: ${({ theme }): string => theme.fontSize};
|
font-size: ${({ theme }: Props): string => theme.fontSize};
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
padding: 0.5rem 0.75rem;
|
padding: 0.5rem 0.75rem;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|||||||
@ -11,7 +11,7 @@ interface Props {
|
|||||||
onClick?: () => void | Promise<void>;
|
onClick?: () => void | Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
function Icon ({ className, icon, onClick }: Props): React.ReactElement<Props> {
|
function Icon ({ className = '', icon, onClick }: Props): React.ReactElement<Props> {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={`${className} icon`}
|
className={`${className} icon`}
|
||||||
|
|||||||
@ -2,6 +2,8 @@
|
|||||||
// This software may be modified and distributed under the terms
|
// This software may be modified and distributed under the terms
|
||||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||||
|
|
||||||
|
import { ThemeProps } from '../types';
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import Icon from '@polkadot/react-identicon';
|
import Icon from '@polkadot/react-identicon';
|
||||||
@ -35,7 +37,7 @@ export default styled(Identicon)`
|
|||||||
|
|
||||||
.container:before {
|
.container:before {
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
background: ${({ theme }): string => theme.identiconBackground};
|
background: ${({ theme }: ThemeProps): string => theme.identiconBackground};
|
||||||
}
|
}
|
||||||
|
|
||||||
svg {
|
svg {
|
||||||
|
|||||||
@ -2,6 +2,8 @@
|
|||||||
// This software may be modified and distributed under the terms
|
// This software may be modified and distributed under the terms
|
||||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||||
|
|
||||||
|
import { ThemeProps } from '../types';
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
|
|
||||||
@ -21,7 +23,7 @@ function Label ({ children, className, label }: Props): React.ReactElement<Props
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default styled(Label)`
|
export default styled(Label)`
|
||||||
color: ${({ theme }): string => theme.textColor};
|
color: ${({ theme }: ThemeProps): string => theme.textColor};
|
||||||
|
|
||||||
label {
|
label {
|
||||||
font-size: 10px;
|
font-size: 10px;
|
||||||
|
|||||||
@ -2,11 +2,13 @@
|
|||||||
// This software may be modified and distributed under the terms
|
// This software may be modified and distributed under the terms
|
||||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||||
|
|
||||||
|
import { ThemeProps } from '../types';
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import { Link as RouterLink } from 'react-router-dom';
|
import { Link as RouterLink } from 'react-router-dom';
|
||||||
|
|
||||||
interface Props {
|
interface Props extends ThemeProps {
|
||||||
children?: React.ReactNode;
|
children?: React.ReactNode;
|
||||||
className?: string;
|
className?: string;
|
||||||
isDanger?: boolean;
|
isDanger?: boolean;
|
||||||
@ -15,8 +17,8 @@ interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function Link ({ children, className, onClick, to }: Props): React.ReactElement<Props> {
|
function Link ({ children, className, onClick, to }: Props): React.ReactElement<Props> {
|
||||||
return (
|
return to
|
||||||
to ? (
|
? (
|
||||||
<RouterLink
|
<RouterLink
|
||||||
className={className}
|
className={className}
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
@ -24,7 +26,8 @@ function Link ({ children, className, onClick, to }: Props): React.ReactElement<
|
|||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</RouterLink>
|
</RouterLink>
|
||||||
) : (
|
)
|
||||||
|
: (
|
||||||
<a
|
<a
|
||||||
className={className}
|
className={className}
|
||||||
href='#'
|
href='#'
|
||||||
@ -32,24 +35,23 @@ function Link ({ children, className, onClick, to }: Props): React.ReactElement<
|
|||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</a>
|
</a>
|
||||||
)
|
);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default styled(Link)`
|
export default styled(Link)`
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
color: ${({ isDanger, theme }): string => isDanger ? theme.textColorDanger : theme.textColor};
|
color: ${({ isDanger, theme }: Props): string => isDanger ? theme.textColorDanger : theme.textColor};
|
||||||
opacity: 0.9;
|
opacity: 0.9;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
color: ${({ isDanger, theme }): string => isDanger ? theme.textColorDanger : theme.textColor};
|
color: ${({ isDanger, theme }: Props): string => isDanger ? theme.textColorDanger : theme.textColor};
|
||||||
opacity: 1.0;
|
opacity: 1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:visited {
|
&:visited {
|
||||||
color: ${({ isDanger, theme }): string => isDanger ? theme.textColorDanger : theme.textColor};
|
color: ${({ isDanger, theme }: Props): string => isDanger ? theme.textColorDanger : theme.textColor};
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|||||||
@ -2,6 +2,8 @@
|
|||||||
// This software may be modified and distributed under the terms
|
// This software may be modified and distributed under the terms
|
||||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||||
|
|
||||||
|
import { ThemeProps } from '../types';
|
||||||
|
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
|
|
||||||
export default styled.ul`
|
export default styled.ul`
|
||||||
@ -17,7 +19,7 @@ export default styled.ul`
|
|||||||
|
|
||||||
li::before {
|
li::before {
|
||||||
content: '\\2022';
|
content: '\\2022';
|
||||||
color: ${({ theme }): string => theme.primaryColor};
|
color: ${({ theme }: ThemeProps): string => theme.primaryColor};
|
||||||
font-size: 30px;
|
font-size: 30px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
|
|||||||
@ -2,6 +2,8 @@
|
|||||||
// This software may be modified and distributed under the terms
|
// This software may be modified and distributed under the terms
|
||||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||||
|
|
||||||
|
import { ThemeProps } from '../types';
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
|
|
||||||
@ -27,10 +29,10 @@ export default styled(Menu)`
|
|||||||
right: 0;
|
right: 0;
|
||||||
margin-top: 90px;
|
margin-top: 90px;
|
||||||
padding: 16px 0;
|
padding: 16px 0;
|
||||||
background: ${({ theme }): string => theme.popupBackground};
|
background: ${({ theme }: ThemeProps): string => theme.popupBackground};
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
border: 1px solid ${({ theme }): string => theme.boxBorderColor};
|
border: 1px solid ${({ theme }: ThemeProps): string => theme.boxBorderColor};
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
box-shadow: 0 0 32px ${({ theme }): string => theme.boxShadow};
|
box-shadow: 0 0 32px ${({ theme }: ThemeProps): string => theme.boxShadow};
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
`;
|
`;
|
||||||
|
|||||||
@ -2,6 +2,8 @@
|
|||||||
// This software may be modified and distributed under the terms
|
// This software may be modified and distributed under the terms
|
||||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||||
|
|
||||||
|
import { ThemeProps } from '../types';
|
||||||
|
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import React, { MouseEventHandler } from 'react';
|
import React, { MouseEventHandler } from 'react';
|
||||||
import TextAreaWithLabel from './TextAreaWithLabel';
|
import TextAreaWithLabel from './TextAreaWithLabel';
|
||||||
@ -35,13 +37,13 @@ const MnemonicText = styled(TextAreaWithLabel).attrs(() => ({
|
|||||||
label: 'Generated 12-word mnemonic seed:'
|
label: 'Generated 12-word mnemonic seed:'
|
||||||
}))`
|
}))`
|
||||||
textarea {
|
textarea {
|
||||||
font-size: ${({ theme }): string => theme.fontSize};
|
font-size: ${({ theme }: ThemeProps): string => theme.fontSize};
|
||||||
line-height: ${({ theme }): string => theme.lineHeight};
|
line-height: ${({ theme }: ThemeProps): string => theme.lineHeight};
|
||||||
height: unset;
|
height: unset;
|
||||||
letter-spacing: -0.01em;
|
letter-spacing: -0.01em;
|
||||||
padding: 14px;
|
padding: 14px;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
color: ${({ theme }): string => theme.primaryColor};
|
color: ${({ theme }: ThemeProps): string => theme.primaryColor};
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|||||||
@ -2,6 +2,8 @@
|
|||||||
// This software may be modified and distributed under the terms
|
// This software may be modified and distributed under the terms
|
||||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||||
|
|
||||||
|
import { ThemeProps } from '../types';
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
|
|
||||||
@ -28,5 +30,5 @@ const ArrowRight = styled(Svg).attrs(() => ({
|
|||||||
height: 12px;
|
height: 12px;
|
||||||
margin: 4px 1px 0 0;
|
margin: 4px 1px 0 0;
|
||||||
transform: rotate(180deg);
|
transform: rotate(180deg);
|
||||||
background: ${({ theme }): string => theme.buttonTextColor};
|
background: ${({ theme }: ThemeProps): string => theme.buttonTextColor};
|
||||||
`;
|
`;
|
||||||
|
|||||||
@ -2,6 +2,8 @@
|
|||||||
// This software may be modified and distributed under the terms
|
// This software may be modified and distributed under the terms
|
||||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||||
|
|
||||||
|
import { ThemeProps } from '../types';
|
||||||
|
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@ -12,5 +14,5 @@ export default styled.span<Props>`
|
|||||||
display: block;
|
display: block;
|
||||||
mask: ${({ src }): string => `url(${src})`};
|
mask: ${({ src }): string => `url(${src})`};
|
||||||
mask-size: cover;
|
mask-size: cover;
|
||||||
background: ${({ theme }): string => theme.textColor};
|
background: ${({ theme }: ThemeProps): string => theme.textColor};
|
||||||
`;
|
`;
|
||||||
|
|||||||
@ -2,6 +2,8 @@
|
|||||||
// This software may be modified and distributed under the terms
|
// This software may be modified and distributed under the terms
|
||||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||||
|
|
||||||
|
import { ThemeProps } from '../types';
|
||||||
|
|
||||||
import React, { useCallback } from 'react';
|
import React, { useCallback } from 'react';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
|
|
||||||
@ -15,7 +17,7 @@ interface Props {
|
|||||||
|
|
||||||
function Switch ({ checked, checkedLabel, className, onChange, uncheckedLabel }: Props): React.ReactElement<Props> {
|
function Switch ({ checked, checkedLabel, className, onChange, uncheckedLabel }: Props): React.ReactElement<Props> {
|
||||||
const _onChange = useCallback(
|
const _onChange = useCallback(
|
||||||
(event) => onChange(event.target.checked),
|
(event: React.ChangeEvent<HTMLInputElement>) => onChange(event.target.checked),
|
||||||
[onChange]
|
[onChange]
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -41,10 +43,10 @@ const Slider = styled.span`
|
|||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
background-color: ${({ theme }): string => theme.readonlyInputBackground};
|
background-color: ${({ theme }: ThemeProps): string => theme.readonlyInputBackground};
|
||||||
transition: 0.2s;
|
transition: 0.2s;
|
||||||
border-radius: 100px;
|
border-radius: 100px;
|
||||||
border: 1px solid ${({ theme }): string => theme.inputBorderColor};
|
border: 1px solid ${({ theme }: ThemeProps): string => theme.inputBorderColor};
|
||||||
|
|
||||||
&:before {
|
&:before {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@ -53,7 +55,7 @@ const Slider = styled.span`
|
|||||||
width: 16px;
|
width: 16px;
|
||||||
left: 4px;
|
left: 4px;
|
||||||
bottom: 3px;
|
bottom: 3px;
|
||||||
background-color: ${({ theme }): string => theme.primaryColor};
|
background-color: ${({ theme }: ThemeProps): string => theme.primaryColor};
|
||||||
transition: 0.4s;
|
transition: 0.4s;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,8 @@
|
|||||||
// This software may be modified and distributed under the terms
|
// This software may be modified and distributed under the terms
|
||||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||||
|
|
||||||
|
import { ThemeProps } from '../types';
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
|
|
||||||
@ -11,9 +13,9 @@ interface Props {
|
|||||||
isFull?: boolean;
|
isFull?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
function Table ({ children, className, isFull }: Props): React.ReactElement<Props> {
|
function Table ({ children, className = '', isFull }: Props): React.ReactElement<Props> {
|
||||||
return (
|
return (
|
||||||
<table className={`${className} ${isFull && 'isFull'}`}>
|
<table className={`${className} ${isFull ? 'isFull' : ''}`}>
|
||||||
<tbody>
|
<tbody>
|
||||||
{children}
|
{children}
|
||||||
</tbody>
|
</tbody>
|
||||||
@ -24,8 +26,8 @@ function Table ({ children, className, isFull }: Props): React.ReactElement<Prop
|
|||||||
export default React.memo(styled(Table)`
|
export default React.memo(styled(Table)`
|
||||||
border: 0;
|
border: 0;
|
||||||
display: block;
|
display: block;
|
||||||
font-size: ${({ theme }): string => theme.labelFontSize};
|
font-size: ${({ theme }: ThemeProps): string => theme.labelFontSize};
|
||||||
line-height: ${({ theme }): string => theme.labelLineHeight};
|
line-height: ${({ theme }: ThemeProps): string => theme.labelLineHeight};
|
||||||
margin-bottom: 1rem;
|
margin-bottom: 1rem;
|
||||||
|
|
||||||
&.isFull {
|
&.isFull {
|
||||||
|
|||||||
@ -2,6 +2,8 @@
|
|||||||
// This software may be modified and distributed under the terms
|
// This software may be modified and distributed under the terms
|
||||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||||
|
|
||||||
|
import { ThemeProps } from '../types';
|
||||||
|
|
||||||
import styled, { css } from 'styled-components';
|
import styled, { css } from 'styled-components';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@ -9,25 +11,25 @@ interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const DefaultTextInputColors = css`
|
const DefaultTextInputColors = css`
|
||||||
background: ${({ theme }): string => theme.inputBackground};
|
background: ${({ theme }: ThemeProps): string => theme.inputBackground};
|
||||||
border-color: ${({ theme }): string => theme.inputBorderColor};
|
border-color: ${({ theme }: ThemeProps): string => theme.inputBorderColor};
|
||||||
color: ${({ theme }): string => theme.textColor};
|
color: ${({ theme }: ThemeProps): string => theme.textColor};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const ErroredTextInputColors = css`
|
const ErroredTextInputColors = css`
|
||||||
background: ${({ theme }): string => theme.inputBackground};
|
background: ${({ theme }: ThemeProps): string => theme.inputBackground};
|
||||||
border-color: ${({ theme }): string => theme.errorBorderColor};
|
border-color: ${({ theme }: ThemeProps): string => theme.errorBorderColor};
|
||||||
color: ${({ theme }): string => theme.errorColor};
|
color: ${({ theme }: ThemeProps): string => theme.errorColor};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const TextInput = css<Props>`
|
const TextInput = css<Props>`
|
||||||
border-radius: ${({ theme }): string => theme.borderRadius};
|
border-radius: ${({ theme }: ThemeProps): string => theme.borderRadius};
|
||||||
border: ${({ theme }): string => `1px solid ${theme.inputBorderColor}`};
|
border: ${({ theme }: ThemeProps): string => `1px solid ${theme.inputBorderColor}`};
|
||||||
outline: none;
|
outline: none;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
display: block;
|
display: block;
|
||||||
font-family: ${({ theme }): string => theme.fontFamily};
|
font-family: ${({ theme }: ThemeProps): string => theme.fontFamily};
|
||||||
font-size: ${({ theme }): string => theme.fontSize};
|
font-size: ${({ theme }: ThemeProps): string => theme.fontSize};
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
height: 40px;
|
height: 40px;
|
||||||
padding: 0.5rem 0.75rem;
|
padding: 0.5rem 0.75rem;
|
||||||
@ -36,7 +38,7 @@ const TextInput = css<Props>`
|
|||||||
${({ withError }): typeof ErroredTextInputColors => (withError ? ErroredTextInputColors : DefaultTextInputColors)};
|
${({ withError }): typeof ErroredTextInputColors => (withError ? ErroredTextInputColors : DefaultTextInputColors)};
|
||||||
|
|
||||||
&:read-only {
|
&:read-only {
|
||||||
background: ${({ theme }): string => theme.readonlyInputBackground};
|
background: ${({ theme }: ThemeProps): string => theme.readonlyInputBackground};
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,8 @@
|
|||||||
// This software may be modified and distributed under the terms
|
// This software may be modified and distributed under the terms
|
||||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||||
|
|
||||||
|
import { ThemeProps } from '../types';
|
||||||
|
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
|
|
||||||
export default styled.div`
|
export default styled.div`
|
||||||
@ -13,6 +15,6 @@ export default styled.div`
|
|||||||
line-height: 14px;
|
line-height: 14px;
|
||||||
letter-spacing: 0.04em;
|
letter-spacing: 0.04em;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
color: ${({ theme }): string => theme.textColor};
|
color: ${({ theme }: ThemeProps): string => theme.textColor};
|
||||||
opacity: 0.65;
|
opacity: 0.65;
|
||||||
`;
|
`;
|
||||||
|
|||||||
@ -2,6 +2,8 @@
|
|||||||
// This software may be modified and distributed under the terms
|
// This software may be modified and distributed under the terms
|
||||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||||
|
|
||||||
|
import { ThemeProps } from '../../types';
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
|
|
||||||
@ -30,6 +32,6 @@ export default styled(Toast)<{visible: boolean}>`
|
|||||||
&& {
|
&& {
|
||||||
margin: auto;
|
margin: auto;
|
||||||
border-radius: 25px;
|
border-radius: 25px;
|
||||||
background: ${({ theme }): string => theme.highlightedAreaBackground};
|
background: ${({ theme }: ThemeProps): string => theme.highlightedAreaBackground};
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|||||||
@ -2,9 +2,11 @@
|
|||||||
// This software may be modified and distributed under the terms
|
// This software may be modified and distributed under the terms
|
||||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||||
|
|
||||||
import React, { useState, useEffect } from 'react';
|
import { ThemeProps } from '../types';
|
||||||
|
|
||||||
|
import React, { useState, useEffect } from 'react';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
|
|
||||||
import { Result, Validator } from '../validators';
|
import { Result, Validator } from '../validators';
|
||||||
|
|
||||||
interface BasicProps {
|
interface BasicProps {
|
||||||
@ -21,7 +23,7 @@ type Props<T extends BasicProps> = T & {
|
|||||||
defaultValue?: string;
|
defaultValue?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
function ValidatedInput<T extends object> ({ className, component: Input, defaultValue, onValidatedChange, validator, ...props }: Props<T>): React.ReactElement<Props<T>> {
|
function ValidatedInput<T extends Record<string, unknown>> ({ className, component: Input, defaultValue, onValidatedChange, validator, ...props }: Props<T>): React.ReactElement<Props<T>> {
|
||||||
const [value, setValue] = useState(defaultValue || '');
|
const [value, setValue] = useState(defaultValue || '');
|
||||||
const [wasMounted, setWasMounted] = useState(false);
|
const [wasMounted, setWasMounted] = useState(false);
|
||||||
const [validationResult, setValidationResult] = useState<Result<string>>(Result.ok(''));
|
const [validationResult, setValidationResult] = useState<Result<string>>(Result.ok(''));
|
||||||
@ -31,6 +33,7 @@ function ValidatedInput<T extends object> ({ className, component: Input, defaul
|
|||||||
setWasMounted(true);
|
setWasMounted(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||||
(async (): Promise<void> => {
|
(async (): Promise<void> => {
|
||||||
const result = await validator(value);
|
const result = await validator(value);
|
||||||
|
|
||||||
@ -43,7 +46,7 @@ function ValidatedInput<T extends object> ({ className, component: Input, defaul
|
|||||||
return (
|
return (
|
||||||
<div className={className}>
|
<div className={className}>
|
||||||
<Input
|
<Input
|
||||||
{...props as T}
|
{...props as unknown as T}
|
||||||
isError={Result.isError(validationResult)}
|
isError={Result.isError(validationResult)}
|
||||||
onChange={setValue}
|
onChange={setValue}
|
||||||
value={value}
|
value={value}
|
||||||
@ -56,9 +59,9 @@ function ValidatedInput<T extends object> ({ className, component: Input, defaul
|
|||||||
const ErrorMessage = styled.span`
|
const ErrorMessage = styled.span`
|
||||||
display: block;
|
display: block;
|
||||||
margin-top: -10px;
|
margin-top: -10px;
|
||||||
font-size: ${({ theme }): string => theme.labelFontSize};
|
font-size: ${({ theme }: ThemeProps): string => theme.labelFontSize};
|
||||||
line-height: ${({ theme }): string => theme.labelLineHeight};
|
line-height: ${({ theme }: ThemeProps): string => theme.labelLineHeight};
|
||||||
color: ${({ theme }): string => theme.errorColor};
|
color: ${({ theme }: ThemeProps): string => theme.errorColor};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
ErrorMessage.displayName = 'ErrorMessage';
|
ErrorMessage.displayName = 'ErrorMessage';
|
||||||
|
|||||||
@ -2,9 +2,13 @@
|
|||||||
// This software may be modified and distributed under the terms
|
// This software may be modified and distributed under the terms
|
||||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||||
|
|
||||||
|
import { ThemeProps } from '../types';
|
||||||
|
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import styled, { ThemeProvider, createGlobalStyle } from 'styled-components';
|
import styled, { ThemeProvider, createGlobalStyle } from 'styled-components';
|
||||||
import { AvailableThemes, chooseTheme, themes, ThemeSwitchContext, Theme } from '.';
|
|
||||||
|
// FIXME We should not import from index when this one is imported there as well
|
||||||
|
import { AvailableThemes, chooseTheme, themes, ThemeSwitchContext } from '.';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
@ -32,9 +36,9 @@ function View ({ children, className }: Props): React.ReactElement<Props> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const BodyTheme = createGlobalStyle<{ theme: Theme }>`
|
const BodyTheme = createGlobalStyle<ThemeProps>`
|
||||||
body {
|
body {
|
||||||
background-color: ${({ theme }): string => theme.bodyColor};
|
background-color: ${({ theme }: ThemeProps): string => theme.bodyColor};
|
||||||
}
|
}
|
||||||
|
|
||||||
html {
|
html {
|
||||||
@ -50,14 +54,14 @@ const Main = styled.main`
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background: ${({ theme }): string => theme.background};
|
background: ${({ theme }: ThemeProps): string => theme.background};
|
||||||
color: ${({ theme }): string => theme.textColor};
|
color: ${({ theme }: ThemeProps): string => theme.textColor};
|
||||||
font-size: ${({ theme }): string => theme.fontSize};
|
font-size: ${({ theme }: ThemeProps): string => theme.fontSize};
|
||||||
line-height: ${({ theme }): string => theme.lineHeight};
|
line-height: ${({ theme }: ThemeProps): string => theme.lineHeight};
|
||||||
border: 1px solid ${({ theme }): string => theme.inputBorderColor};
|
border: 1px solid ${({ theme }: ThemeProps): string => theme.inputBorderColor};
|
||||||
|
|
||||||
* {
|
* {
|
||||||
font-family: ${({ theme }): string => theme.fontFamily};
|
font-family: ${({ theme }: ThemeProps): string => theme.fontFamily};
|
||||||
}
|
}
|
||||||
|
|
||||||
> * {
|
> * {
|
||||||
|
|||||||
@ -2,45 +2,46 @@
|
|||||||
// This software may be modified and distributed under the terms
|
// This software may be modified and distributed under the terms
|
||||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||||
|
|
||||||
|
import { ThemeProps } from '../types';
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import WarningImageSrc from '../assets/warning.svg';
|
|
||||||
import Svg from '@polkadot/extension-ui/components/Svg';
|
|
||||||
|
|
||||||
interface Props {
|
import warningImageSrc from '../assets/warning.svg';
|
||||||
|
import Svg from './Svg';
|
||||||
|
|
||||||
|
interface Props extends ThemeProps {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
danger?: boolean;
|
danger?: boolean;
|
||||||
className?: string;
|
className?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
function Warning ({ children, className, danger }: Props): React.ReactElement<Props> {
|
function Warning ({ children, className }: Props): React.ReactElement<Props> {
|
||||||
return (
|
return (
|
||||||
<div className={className}>
|
<div className={className}>
|
||||||
<div>
|
<div>
|
||||||
<WarningImage
|
<Svg
|
||||||
danger={danger}
|
className='warningImage'
|
||||||
src={WarningImageSrc}
|
src={warningImageSrc}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>{children}</div>
|
||||||
{children}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const WarningImage = styled(Svg)<Pick<Props, 'danger'>>`
|
export default React.memo(styled(Warning)`
|
||||||
width: 16px;
|
|
||||||
height: 14px;
|
|
||||||
margin: 5px 10px 5px 0;
|
|
||||||
background: ${({ danger, theme }): string => danger ? theme.iconDangerColor : theme.iconWarningColor};
|
|
||||||
`;
|
|
||||||
|
|
||||||
export default styled(Warning)`
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
padding-left: ${({ danger }): string => danger ? '18px' : ''};
|
padding-left: ${({ danger }): string => danger ? '18px' : ''};
|
||||||
color: ${({ theme }): string => theme.subTextColor};
|
color: ${({ theme }: Props): string => theme.subTextColor};
|
||||||
margin-right: 20px;
|
margin-right: 20px;
|
||||||
border-left: ${({ danger, theme }): string => danger ? `0.25rem solid ${theme.buttonBackgroundDanger}` : ''};
|
border-left: ${({ danger, theme }: Props): string => danger ? `0.25rem solid ${theme.buttonBackgroundDanger}` : ''};
|
||||||
`;
|
|
||||||
|
.warningImage {
|
||||||
|
width: 16px;
|
||||||
|
height: 14px;
|
||||||
|
margin: 5px 10px 5px 0;
|
||||||
|
background: ${({ danger, theme }: Props): string => danger ? theme.iconDangerColor : theme.iconWarningColor};
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
|||||||
@ -76,12 +76,14 @@ export function chooseTheme (): AvailableThemes {
|
|||||||
const preferredTheme = localStorage.getItem('theme');
|
const preferredTheme = localStorage.getItem('theme');
|
||||||
|
|
||||||
if (preferredTheme) {
|
if (preferredTheme) {
|
||||||
return preferredTheme === 'dark' ? 'dark' : 'light';
|
return preferredTheme === 'dark'
|
||||||
|
? 'dark'
|
||||||
|
: 'light';
|
||||||
}
|
}
|
||||||
|
|
||||||
const isLightColorSchemePreferred = window.matchMedia && window.matchMedia('(prefers-color-scheme: light)').matches;
|
return window.matchMedia && window.matchMedia('(prefers-color-scheme: light)').matches
|
||||||
|
? 'light'
|
||||||
return isLightColorSchemePreferred ? 'light' : 'dark';
|
: 'dark';
|
||||||
}
|
}
|
||||||
|
|
||||||
export declare type Theme = typeof darkTheme;
|
export declare type Theme = typeof darkTheme;
|
||||||
|
|||||||
@ -12,7 +12,7 @@ export default function useMetadata (genesisHash?: string | null): Chain | null
|
|||||||
const [chain, setChain] = useState<Chain | null>(null);
|
const [chain, setChain] = useState<Chain | null>(null);
|
||||||
|
|
||||||
useEffect((): void => {
|
useEffect((): void => {
|
||||||
getMetadata(genesisHash).then(setChain);
|
getMetadata(genesisHash).then(setChain).catch(console.error);
|
||||||
}, [genesisHash]);
|
}, [genesisHash]);
|
||||||
|
|
||||||
return chain;
|
return chain;
|
||||||
|
|||||||
@ -17,7 +17,7 @@ describe('messaging sends message to background via extension port for', () => {
|
|||||||
const callback = jest.fn();
|
const callback = jest.fn();
|
||||||
|
|
||||||
chrome.runtime.connect().onMessage.addListener(callback);
|
chrome.runtime.connect().onMessage.addListener(callback);
|
||||||
exportAccount('HjoBp62cvsWDA3vtNMWxz6c9q13ReEHi9UGHK7JbZweH5g5', 'passw0rd');
|
exportAccount('HjoBp62cvsWDA3vtNMWxz6c9q13ReEHi9UGHK7JbZweH5g5', 'passw0rd').catch(console.error);
|
||||||
|
|
||||||
expect(callback).toHaveBeenCalledWith(
|
expect(callback).toHaveBeenCalledWith(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
// This software may be modified and distributed under the terms
|
// This software may be modified and distributed under the terms
|
||||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||||
|
|
||||||
|
import { Message } from '@polkadot/extension-base/types';
|
||||||
import { AccountJson, AuthorizeRequest, SigningRequest, RequestTypes, MessageTypes, ResponseTypes, SeedLengths, SubscriptionMessageTypes, MetadataRequest, MessageTypesWithNullRequest, MessageTypesWithNoSubscriptions, MessageTypesWithSubscriptions, ResponseDeriveValidate } from '@polkadot/extension-base/background/types';
|
import { AccountJson, AuthorizeRequest, SigningRequest, RequestTypes, MessageTypes, ResponseTypes, SeedLengths, SubscriptionMessageTypes, MetadataRequest, MessageTypesWithNullRequest, MessageTypesWithNoSubscriptions, MessageTypesWithSubscriptions, ResponseDeriveValidate } from '@polkadot/extension-base/background/types';
|
||||||
import { Chain } from '@polkadot/extension-chains/types';
|
import { Chain } from '@polkadot/extension-chains/types';
|
||||||
import { KeypairType } from '@polkadot/util-crypto/types';
|
import { KeypairType } from '@polkadot/util-crypto/types';
|
||||||
@ -25,7 +26,7 @@ const handlers: Handlers = {};
|
|||||||
let idCounter = 0;
|
let idCounter = 0;
|
||||||
|
|
||||||
// setup a listener for messages, any incoming resolves the promise
|
// setup a listener for messages, any incoming resolves the promise
|
||||||
port.onMessage.addListener((data): void => {
|
port.onMessage.addListener((data: Message['data']): void => {
|
||||||
const handler = handlers[data.id];
|
const handler = handlers[data.id];
|
||||||
|
|
||||||
if (!handler) {
|
if (!handler) {
|
||||||
@ -39,6 +40,7 @@ port.onMessage.addListener((data): void => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (data.subscription) {
|
if (data.subscription) {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||||
(handler.subscriber as Function)(data.subscription);
|
(handler.subscriber as Function)(data.subscription);
|
||||||
} else if (data.error) {
|
} else if (data.error) {
|
||||||
handler.reject(new Error(data.error));
|
handler.reject(new Error(data.error));
|
||||||
@ -50,8 +52,7 @@ port.onMessage.addListener((data): void => {
|
|||||||
function sendMessage<TMessageType extends MessageTypesWithNullRequest>(message: TMessageType): Promise<ResponseTypes[TMessageType]>;
|
function sendMessage<TMessageType extends MessageTypesWithNullRequest>(message: TMessageType): Promise<ResponseTypes[TMessageType]>;
|
||||||
function sendMessage<TMessageType extends MessageTypesWithNoSubscriptions>(message: TMessageType, request: RequestTypes[TMessageType]): Promise<ResponseTypes[TMessageType]>;
|
function sendMessage<TMessageType extends MessageTypesWithNoSubscriptions>(message: TMessageType, request: RequestTypes[TMessageType]): Promise<ResponseTypes[TMessageType]>;
|
||||||
function sendMessage<TMessageType extends MessageTypesWithSubscriptions>(message: TMessageType, request: RequestTypes[TMessageType], subscriber: (data: SubscriptionMessageTypes[TMessageType]) => void): Promise<ResponseTypes[TMessageType]>;
|
function sendMessage<TMessageType extends MessageTypesWithSubscriptions>(message: TMessageType, request: RequestTypes[TMessageType], subscriber: (data: SubscriptionMessageTypes[TMessageType]) => void): Promise<ResponseTypes[TMessageType]>;
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
function sendMessage<TMessageType extends MessageTypes> (message: TMessageType, request?: RequestTypes[TMessageType], subscriber?: (data: unknown) => void): Promise<ResponseTypes[TMessageType]> {
|
||||||
function sendMessage<TMessageType extends MessageTypes> (message: TMessageType, request?: RequestTypes[TMessageType], subscriber?: (data: any) => void): Promise<ResponseTypes[TMessageType]> {
|
|
||||||
return new Promise((resolve, reject): void => {
|
return new Promise((resolve, reject): void => {
|
||||||
const id = `${Date.now()}.${++idCounter}`;
|
const id = `${Date.now()}.${++idCounter}`;
|
||||||
|
|
||||||
|
|||||||
@ -2,6 +2,8 @@
|
|||||||
// This software may be modified and distributed under the terms
|
// This software may be modified and distributed under the terms
|
||||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||||
|
|
||||||
|
import { ThemeProps } from '../types';
|
||||||
|
|
||||||
import React, { useCallback, useContext } from 'react';
|
import React, { useCallback, useContext } from 'react';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
|
|
||||||
@ -43,7 +45,7 @@ const TipText = styled.p`
|
|||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
line-height: 26px;
|
line-height: 26px;
|
||||||
margin: 0 30px;
|
margin: 0 30px;
|
||||||
color: ${({ theme }): string => theme.subTextColor};
|
color: ${({ theme }: ThemeProps): string => theme.subTextColor};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const Image = styled.div`
|
const Image = styled.div`
|
||||||
@ -52,11 +54,11 @@ const Image = styled.div`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
export default styled(AddAccount)`
|
export default styled(AddAccount)`
|
||||||
color: ${({ theme }): string => theme.textColor};
|
color: ${({ theme }: ThemeProps): string => theme.textColor};
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
||||||
h3 {
|
h3 {
|
||||||
color: ${({ theme }): string => theme.textColor};
|
color: ${({ theme }: ThemeProps): string => theme.textColor};
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
|
|||||||
@ -8,10 +8,12 @@
|
|||||||
/* eslint-disable react/jsx-sort-props */
|
/* eslint-disable react/jsx-sort-props */
|
||||||
/* eslint-disable react/jsx-max-props-per-line */
|
/* eslint-disable react/jsx-max-props-per-line */
|
||||||
|
|
||||||
|
import { ThemeProps } from '../types';
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
|
|
||||||
interface Props {
|
interface Props extends ThemeProps {
|
||||||
className?: string;
|
className?: string;
|
||||||
onClick: () => void;
|
onClick: () => void;
|
||||||
}
|
}
|
||||||
@ -73,11 +75,11 @@ export default styled(AddAccountImage)`
|
|||||||
}
|
}
|
||||||
|
|
||||||
path {
|
path {
|
||||||
fill: ${({ theme }): string => theme.textColor};
|
fill: ${({ theme }: Props): string => theme.textColor};
|
||||||
}
|
}
|
||||||
|
|
||||||
& > g > circle {
|
& > g > circle {
|
||||||
stroke: ${({ theme }): string => theme.inputBorderColor};
|
stroke: ${({ theme }: Props): string => theme.inputBorderColor};
|
||||||
fill: ${({ theme }): string => theme.addAccountImageBackground};
|
fill: ${({ theme }: Props): string => theme.addAccountImageBackground};
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|||||||
@ -2,6 +2,8 @@
|
|||||||
// This software may be modified and distributed under the terms
|
// This software may be modified and distributed under the terms
|
||||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||||
|
|
||||||
|
import { ThemeProps } from '../types';
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
|
|
||||||
@ -28,22 +30,22 @@ const ArrowLeft = styled(Svg).attrs(() => ({ src: ArrowLeftImage }))`
|
|||||||
width: 12px;
|
width: 12px;
|
||||||
height: 12px;
|
height: 12px;
|
||||||
margin-right: 13px;
|
margin-right: 13px;
|
||||||
background: ${({ theme }): string => theme.labelColor};
|
background: ${({ theme }: ThemeProps) => theme.labelColor};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const BackLink = styled(Link)`
|
const BackLink = styled(Link)`
|
||||||
width: min-content;
|
width: min-content;
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
color: ${({ theme }): string => theme.labelColor};
|
color: ${({ theme }: ThemeProps) => theme.labelColor};
|
||||||
|
|
||||||
&:visited {
|
&:visited {
|
||||||
color: ${({ theme }): string => theme.labelColor};
|
color: ${({ theme }: ThemeProps) => theme.labelColor};
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export default styled(Back)`
|
export default styled(Back)`
|
||||||
margin: 0;
|
margin: 0;
|
||||||
line-height: 52px;
|
line-height: 52px;
|
||||||
border-bottom: 1px solid ${({ theme }): string => theme.inputBorderColor};
|
border-bottom: 1px solid ${({ theme }: ThemeProps): string => theme.inputBorderColor};
|
||||||
font-size: ${({ theme }): string => theme.labelFontSize};
|
font-size: ${({ theme }: ThemeProps): string => theme.labelFontSize};
|
||||||
`;
|
`;
|
||||||
|
|||||||
@ -2,6 +2,8 @@
|
|||||||
// This software may be modified and distributed under the terms
|
// This software may be modified and distributed under the terms
|
||||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||||
|
|
||||||
|
import { ThemeProps } from '../types';
|
||||||
|
|
||||||
import React, { useCallback, useState } from 'react';
|
import React, { useCallback, useState } from 'react';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
|
|
||||||
@ -90,7 +92,7 @@ const LockIcon = styled(Svg).attrs(() => ({
|
|||||||
}))`
|
}))`
|
||||||
width: 11px;
|
width: 11px;
|
||||||
height: 14px;
|
height: 14px;
|
||||||
background: ${({ theme }): string => theme.iconNeutralColor};
|
background: ${({ theme }: ThemeProps) => theme.iconNeutralColor};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const UnlockIcon = styled(Svg).attrs(() => ({
|
const UnlockIcon = styled(Svg).attrs(() => ({
|
||||||
@ -98,7 +100,7 @@ const UnlockIcon = styled(Svg).attrs(() => ({
|
|||||||
}))`
|
}))`
|
||||||
width: 11px;
|
width: 11px;
|
||||||
height: 14px;
|
height: 14px;
|
||||||
background: ${({ theme }): string => theme.iconNeutralColor};
|
background: ${({ theme }: ThemeProps) => theme.iconNeutralColor};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const LockButton = styled(Button)`
|
const LockButton = styled(Button)`
|
||||||
|
|||||||
@ -18,6 +18,7 @@ configure({ adapter: new Adapter() });
|
|||||||
|
|
||||||
describe('Header component', () => {
|
describe('Header component', () => {
|
||||||
let wrapper: ReactWrapper;
|
let wrapper: ReactWrapper;
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
||||||
const mountHeader = (props: React.ComponentProps<typeof Header> = {}): ReactWrapper => mount(
|
const mountHeader = (props: React.ComponentProps<typeof Header> = {}): ReactWrapper => mount(
|
||||||
<MemoryRouter>
|
<MemoryRouter>
|
||||||
<ThemeProvider theme={themes.dark}>
|
<ThemeProvider theme={themes.dark}>
|
||||||
|
|||||||
@ -2,6 +2,8 @@
|
|||||||
// This software may be modified and distributed under the terms
|
// This software may be modified and distributed under the terms
|
||||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||||
|
|
||||||
|
import { ThemeProps } from '../types';
|
||||||
|
|
||||||
import React, { useCallback, useRef, useState } from 'react';
|
import React, { useCallback, useRef, useState } from 'react';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
|
|
||||||
@ -62,28 +64,26 @@ function Header ({ children, className, showBackArrow, showSettings, text }: Pro
|
|||||||
const BackLink = styled(Link)`
|
const BackLink = styled(Link)`
|
||||||
width: min-content;
|
width: min-content;
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
color: ${({ theme }): string => theme.labelColor};
|
color: ${({ theme }: ThemeProps) => theme.labelColor};
|
||||||
min-height: 52px;
|
min-height: 52px;
|
||||||
|
|
||||||
&:visited {
|
&:visited {
|
||||||
color: ${({ theme }): string => theme.labelColor};
|
color: ${({ theme }: ThemeProps) => theme.labelColor};
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const ArrowLeft = styled(Svg).attrs(() => ({
|
const ArrowLeft = styled(Svg).attrs(() => ({ src: ArrowLeftImage }))`
|
||||||
src: ArrowLeftImage
|
|
||||||
}))`
|
|
||||||
width: 12px;
|
width: 12px;
|
||||||
height: 12px;
|
height: 12px;
|
||||||
margin-right: 13px;
|
margin-right: 13px;
|
||||||
background: ${({ theme }): string => theme.labelColor};
|
background: ${({ theme }: ThemeProps) => theme.labelColor};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const Container = styled.div`
|
const Container = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border-bottom: 1px solid ${({ theme }): string => theme.inputBorderColor};
|
border-bottom: 1px solid ${({ theme }: ThemeProps) => theme.inputBorderColor};
|
||||||
min-height: 70px;
|
min-height: 70px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@ -91,8 +91,8 @@ const Branding = styled.div`
|
|||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
color: ${({ theme }): string => theme.labelColor};
|
color: ${({ theme }: ThemeProps) => theme.labelColor};
|
||||||
font-family: ${({ theme }): string => theme.fontFamily};
|
font-family: ${({ theme }: ThemeProps) => theme.fontFamily};
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin-left: 24px;
|
margin-left: 24px;
|
||||||
`;
|
`;
|
||||||
@ -107,21 +107,19 @@ interface GearProps {
|
|||||||
isSelected: boolean;
|
isSelected: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Gear = styled(Svg).attrs(() => ({
|
const Gear = styled(Svg).attrs(() => ({ src: gear }))<GearProps>`
|
||||||
src: gear
|
|
||||||
}))<GearProps>`
|
|
||||||
height: 18px;
|
height: 18px;
|
||||||
width: 18px;
|
width: 18px;
|
||||||
margin-right: 24px;
|
margin-right: 24px;
|
||||||
align-self: center;
|
align-self: center;
|
||||||
background: ${({ isSelected, theme }): string => isSelected ? theme.primaryColor : theme.iconNeutralColor};
|
background: ${({ isSelected, theme }: ThemeProps & GearProps): string => isSelected ? theme.primaryColor : theme.iconNeutralColor};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
Gear.displayName = 'Gear';
|
Gear.displayName = 'Gear';
|
||||||
|
|
||||||
const LogoText = styled.span`
|
const LogoText = styled.span`
|
||||||
color: ${({ theme }): string => theme.textColor};
|
color: ${({ theme }: ThemeProps) => theme.textColor};
|
||||||
font-family: ${({ theme }): string => theme.fontFamily};
|
font-family: ${({ theme }: ThemeProps) => theme.fontFamily};
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
line-height: 27px;
|
line-height: 27px;
|
||||||
`;
|
`;
|
||||||
|
|||||||
@ -2,6 +2,8 @@
|
|||||||
// This software may be modified and distributed under the terms
|
// This software may be modified and distributed under the terms
|
||||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||||
|
|
||||||
|
import { ThemeProps } from '../types';
|
||||||
|
|
||||||
import React, { useCallback, useContext } from 'react';
|
import React, { useCallback, useContext } from 'react';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
|
|
||||||
@ -46,15 +48,15 @@ const CreationSteps = styled.div`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
const CurrentStep = styled.span`
|
const CurrentStep = styled.span`
|
||||||
font-size: ${({ theme }): string => theme.labelFontSize};
|
font-size: ${({ theme }: ThemeProps) => theme.labelFontSize};
|
||||||
line-height: ${({ theme }): string => theme.labelLineHeight};
|
line-height: ${({ theme }: ThemeProps) => theme.labelLineHeight};
|
||||||
color: ${({ theme }): string => theme.primaryColor};
|
color: ${({ theme }: ThemeProps) => theme.primaryColor};
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const TotalSteps = styled.span`
|
const TotalSteps = styled.span`
|
||||||
font-size: ${({ theme }): string => theme.labelFontSize};
|
font-size: ${({ theme }: ThemeProps) => theme.labelFontSize};
|
||||||
line-height: ${({ theme }): string => theme.labelLineHeight};
|
line-height: ${({ theme }: ThemeProps) => theme.labelLineHeight};
|
||||||
color: ${({ theme }): string => theme.textColor};
|
color: ${({ theme }: ThemeProps) => theme.textColor};
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
`;
|
`;
|
||||||
|
|||||||
@ -2,6 +2,8 @@
|
|||||||
// This software may be modified and distributed under the terms
|
// This software may be modified and distributed under the terms
|
||||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||||
|
|
||||||
|
import { Theme, ThemeProps } from '../types';
|
||||||
|
|
||||||
import React, { useCallback, useContext, useState, useEffect } from 'react';
|
import React, { useCallback, useContext, useState, useEffect } from 'react';
|
||||||
import styled, { ThemeContext } from 'styled-components';
|
import styled, { ThemeContext } from 'styled-components';
|
||||||
import { setSS58Format } from '@polkadot/util-crypto';
|
import { setSS58Format } from '@polkadot/util-crypto';
|
||||||
@ -16,6 +18,11 @@ interface Option {
|
|||||||
value: string;
|
value: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface Props extends ThemeProps {
|
||||||
|
className?: string;
|
||||||
|
reference: React.MutableRefObject<null>;
|
||||||
|
}
|
||||||
|
|
||||||
const isPopup = window.innerWidth <= 480;
|
const isPopup = window.innerWidth <= 480;
|
||||||
const prefixOptions = settings.availablePrefixes.map(({ text, value }): Option => ({
|
const prefixOptions = settings.availablePrefixes.map(({ text, value }): Option => ({
|
||||||
text: value === -1
|
text: value === -1
|
||||||
@ -24,10 +31,10 @@ const prefixOptions = settings.availablePrefixes.map(({ text, value }): Option =
|
|||||||
value: `${value}`
|
value: `${value}`
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export default function Settings ({ reference }: { reference: React.MutableRefObject<null> }): React.ReactElement {
|
function Settings ({ className, reference }: Props): React.ReactElement<Props> {
|
||||||
const [camera, setCamera] = useState(settings.camera === 'on');
|
const [camera, setCamera] = useState(settings.camera === 'on');
|
||||||
const [prefix, setPrefix] = useState(`${settings.prefix}`);
|
const [prefix, setPrefix] = useState(`${settings.prefix}`);
|
||||||
const themeContext = useContext(ThemeContext);
|
const themeContext = useContext<Theme>(ThemeContext);
|
||||||
const setTheme = useContext(ThemeSwitchContext);
|
const setTheme = useContext(ThemeSwitchContext);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -56,7 +63,10 @@ export default function Settings ({ reference }: { reference: React.MutableRefOb
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SettingsMenu reference={reference}>
|
<Menu
|
||||||
|
className={className}
|
||||||
|
reference={reference}
|
||||||
|
>
|
||||||
<Setting>
|
<Setting>
|
||||||
<SettingTitle>Theme</SettingTitle>
|
<SettingTitle>Theme</SettingTitle>
|
||||||
<Switch
|
<Switch
|
||||||
@ -92,28 +102,22 @@ export default function Settings ({ reference }: { reference: React.MutableRefOb
|
|||||||
/>
|
/>
|
||||||
</Setting>
|
</Setting>
|
||||||
)}
|
)}
|
||||||
</SettingsMenu>
|
</Menu>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const SettingsMenu = styled(Menu)`
|
|
||||||
margin-top: 56px;
|
|
||||||
right: 24px;
|
|
||||||
user-select: none;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const CheckboxSetting = styled(Checkbox)`
|
const CheckboxSetting = styled(Checkbox)`
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
line-height: 20px;
|
line-height: 20px;
|
||||||
color: ${({ theme }): string => theme.textColor};
|
color: ${({ theme }: ThemeProps) => theme.textColor};
|
||||||
label {
|
label {
|
||||||
color: ${({ theme }): string => theme.textColor};
|
color: ${({ theme }: ThemeProps) => theme.textColor};
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const DropdownSetting = styled(Dropdown)`
|
const DropdownSetting = styled(Dropdown)`
|
||||||
background: ${({ theme }): string => theme.background};
|
background: ${({ theme }: ThemeProps) => theme.background};
|
||||||
margin-top: 9px;
|
margin-top: 9px;
|
||||||
margin-bottom: 12px;
|
margin-bottom: 12px;
|
||||||
width : 100%;
|
width : 100%;
|
||||||
@ -125,27 +129,38 @@ const SettingTitle = styled(Title)`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
const Setting = styled.div`
|
const Setting = styled.div`
|
||||||
padding: 0 16px;
|
|
||||||
max-width: 100%;
|
|
||||||
& + & {
|
|
||||||
padding-top: 18px;
|
|
||||||
border-top: 1px solid ${({ theme }): string => theme.inputBorderColor};
|
|
||||||
}
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const OpenInNewWindowButton = styled(ActionText)`
|
const OpenInNewWindowButton = styled(ActionText)`
|
||||||
span {
|
span {
|
||||||
color: ${({ theme }): string => theme.textColor};
|
color: ${({ theme }: ThemeProps) => theme.textColor};
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
font-size: ${({ theme }): string => theme.fontSize};
|
font-size: ${({ theme }: ThemeProps) => theme.fontSize};
|
||||||
line-height: ${({ theme }): string => theme.lineHeight};
|
line-height: ${({ theme }: ThemeProps) => theme.lineHeight};
|
||||||
}
|
}
|
||||||
|
|
||||||
${Svg} {
|
${Svg} {
|
||||||
width: 20px;
|
width: 20px;
|
||||||
height: 20px;
|
height: 20px;
|
||||||
top: 4px;
|
top: 4px;
|
||||||
background: ${({ theme }): string => theme.textColor};
|
background: ${({ theme }: ThemeProps) => theme.textColor};
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
export default React.memo(styled(Settings)`
|
||||||
|
margin-top: 56px;
|
||||||
|
right: 24px;
|
||||||
|
user-select: none;
|
||||||
|
|
||||||
|
.setting {
|
||||||
|
padding: 0 16px;
|
||||||
|
max-width: 100%;
|
||||||
|
|
||||||
|
& + & {
|
||||||
|
padding-top: 18px;
|
||||||
|
border-top: 1px solid ${({ theme }: Props): string => theme.inputBorderColor};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
|||||||
11
packages/extension-ui/src/types.ts
Normal file
11
packages/extension-ui/src/types.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
// Copyright 2019-2020 @polkadot/extension-ui authors & contributors
|
||||||
|
// This software may be modified and distributed under the terms
|
||||||
|
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||||
|
|
||||||
|
import { Theme } from './components/themes';
|
||||||
|
|
||||||
|
export { Theme };
|
||||||
|
|
||||||
|
export interface ThemeProps {
|
||||||
|
theme: Theme;
|
||||||
|
}
|
||||||
@ -11,7 +11,7 @@
|
|||||||
"@polkadot/extension-ui": "0.26.0-beta.2"
|
"@polkadot/extension-ui": "0.26.0-beta.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@polkadot/dev": "^0.53.5",
|
"@polkadot/dev": "^0.54.1",
|
||||||
"babel-loader": "^8.1.0",
|
"babel-loader": "^8.1.0",
|
||||||
"extract-loader": "^5.0.1",
|
"extract-loader": "^5.0.1",
|
||||||
"file-loader": "^6.0.0",
|
"file-loader": "^6.0.0",
|
||||||
|
|||||||
@ -2,6 +2,8 @@
|
|||||||
// This software may be modified and distributed under the terms
|
// This software may be modified and distributed under the terms
|
||||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||||
|
|
||||||
|
import { Message } from '@polkadot/extension-base/types';
|
||||||
|
|
||||||
import { PORT_CONTENT } from '@polkadot/extension-base/defaults';
|
import { PORT_CONTENT } from '@polkadot/extension-base/defaults';
|
||||||
import chrome from '@polkadot/extension-inject/chrome';
|
import chrome from '@polkadot/extension-inject/chrome';
|
||||||
|
|
||||||
@ -14,7 +16,7 @@ port.onMessage.addListener((data): void => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// all messages from the page, pass them to the extension
|
// all messages from the page, pass them to the extension
|
||||||
window.addEventListener('message', ({ data, source }): void => {
|
window.addEventListener('message', ({ data, source }: Message): void => {
|
||||||
// only allow messages from our window, by the inject
|
// only allow messages from our window, by the inject
|
||||||
if (source !== window || data.origin !== 'page') {
|
if (source !== window || data.origin !== 'page') {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@ -2,18 +2,21 @@
|
|||||||
// This software may be modified and distributed under the terms
|
// This software may be modified and distributed under the terms
|
||||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||||
|
|
||||||
|
import { Message } from '@polkadot/extension-base/types';
|
||||||
|
|
||||||
import { enable, handleResponse } from '@polkadot/extension-base/page';
|
import { enable, handleResponse } from '@polkadot/extension-base/page';
|
||||||
import { injectExtension } from '@polkadot/extension-inject';
|
import { injectExtension } from '@polkadot/extension-inject';
|
||||||
|
|
||||||
// setup a response listener (events created by the loader for extension responses)
|
// setup a response listener (events created by the loader for extension responses)
|
||||||
window.addEventListener('message', ({ data, source }): void => {
|
window.addEventListener('message', ({ data, source }: Message): void => {
|
||||||
// only allow messages from our window, by the loader
|
// only allow messages from our window, by the loader
|
||||||
if (source !== window || data.origin !== 'content') {
|
if (source !== window || data.origin !== 'content') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.id) {
|
if (data.id) {
|
||||||
handleResponse(data);
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
handleResponse(data as any);
|
||||||
} else {
|
} else {
|
||||||
console.error('Missing id for response.');
|
console.error('Missing id for response.');
|
||||||
}
|
}
|
||||||
|
|||||||
@ -61,7 +61,6 @@ function createWebpack ({ alias = {}, context }) {
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
node: {
|
node: {
|
||||||
// eslint-disable-next-line @typescript-eslint/camelcase
|
|
||||||
child_process: 'empty',
|
child_process: 'empty',
|
||||||
dgram: 'empty',
|
dgram: 'empty',
|
||||||
fs: 'empty',
|
fs: 'empty',
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user