mirror of
https://github.com/pezkuwichain/pezkuwi-ui.git
synced 2026-11-12 21:57:09 +00:00
Move to @pezkuwi/dev 0.86 (eslint 10 toolchain)
- @pezkuwi/dev, dev-test, dev-ts ^0.86.3 - react-qr Display: the frames follow the value's content (xxhash), are reset while rendering instead of in an effect, and the frame timer is keyed on the frame set. Before, a value that went from one frame to several never started animating; Display.spec covers single, multi, single-to-multi and unmount. tsconfig build/spec know *.spec.tsx. - optional calls instead of guard expressions (ScanAddress, stores) - KeyringOptions as a Record; type assertions the receiver already accepts removed (Settings, vue-identicon) - disable directives narrowed to the rules that still report
This commit is contained in:
1 parent
6ee748883a
commit
5a542f2805
18 files changed
+2861
-3172
No files matched your search
+1
-1
@@ -33,7 +33,7 @@
|
|||||||
"test:one": "pezkuwi-dev-run-test --env browser"
|
"test:one": "pezkuwi-dev-run-test --env browser"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@pezkuwi/dev": "^0.85.12",
|
"@pezkuwi/dev": "^0.86.3",
|
||||||
"@pezkuwi/x-bundle": "^14.0.26",
|
"@pezkuwi/x-bundle": "^14.0.26",
|
||||||
"@types/node": "^22.10.5",
|
"@types/node": "^22.10.5",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
|
|||||||
@@ -0,0 +1,135 @@
|
|||||||
|
// Copyright 2017-2026 @pezkuwi/react-qr authors & contributors
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
/// <reference types="@pezkuwi/dev-test/globals.d.ts" />
|
||||||
|
|
||||||
|
import React, { act } from 'react';
|
||||||
|
import { createRoot } from 'react-dom/client';
|
||||||
|
|
||||||
|
import { QrDisplay } from './Display.js';
|
||||||
|
|
||||||
|
// Bytes, so that a payload of this size is split into several QR frames.
|
||||||
|
const MULTI = new Uint8Array(4096).map((_, i) => i % 256);
|
||||||
|
const SINGLE = new Uint8Array([1, 2, 3, 4]);
|
||||||
|
const DELAY = 40;
|
||||||
|
|
||||||
|
function sleep (ms: number): Promise<void> {
|
||||||
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||||
|
}
|
||||||
|
|
||||||
|
function setup () {
|
||||||
|
(globalThis as unknown as { IS_REACT_ACT_ENVIRONMENT: boolean }).IS_REACT_ACT_ENVIRONMENT = true;
|
||||||
|
|
||||||
|
const el = document.createElement('div');
|
||||||
|
const root = createRoot(el);
|
||||||
|
const src = (): string | null => el.querySelector('img')?.getAttribute('src') ?? null;
|
||||||
|
|
||||||
|
return { el, root, src };
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Every distinct image shown while waiting `ms`. */
|
||||||
|
async function imagesDuring (src: () => string | null, ms: number): Promise<Set<string>> {
|
||||||
|
const seen = new Set<string>();
|
||||||
|
|
||||||
|
for (let t = 0; t < ms; t += DELAY / 2) {
|
||||||
|
await act(async () => {
|
||||||
|
await sleep(DELAY / 2);
|
||||||
|
});
|
||||||
|
|
||||||
|
const s = src();
|
||||||
|
|
||||||
|
s && seen.add(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
return seen;
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('QrDisplay', (): void => {
|
||||||
|
it('shows a single frame and keeps it', async (): Promise<void> => {
|
||||||
|
const { root, src } = setup();
|
||||||
|
|
||||||
|
act(() => {
|
||||||
|
root.render(
|
||||||
|
<QrDisplay
|
||||||
|
timerDelay={DELAY}
|
||||||
|
value={SINGLE}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
expect({ image: src()?.startsWith('data:image/'), test: 'single' }).toEqual({ image: true, test: 'single' });
|
||||||
|
expect({ frames: (await imagesDuring(src, DELAY * 4)).size, test: 'single' }).toEqual({ frames: 1, test: 'single' });
|
||||||
|
|
||||||
|
act(() => {
|
||||||
|
root.unmount();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('cycles through the frames of a multi-frame payload', async (): Promise<void> => {
|
||||||
|
const { root, src } = setup();
|
||||||
|
|
||||||
|
act(() => {
|
||||||
|
root.render(
|
||||||
|
<QrDisplay
|
||||||
|
skipEncoding={false}
|
||||||
|
timerDelay={DELAY}
|
||||||
|
value={MULTI}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
expect({ cycles: (await imagesDuring(src, DELAY * 6)).size > 1, test: 'multi' }).toEqual({ cycles: true, test: 'multi' });
|
||||||
|
|
||||||
|
act(() => {
|
||||||
|
root.unmount();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('starts cycling when a single-frame value becomes a multi-frame one', async (): Promise<void> => {
|
||||||
|
const { root, src } = setup();
|
||||||
|
|
||||||
|
act(() => {
|
||||||
|
root.render(
|
||||||
|
<QrDisplay
|
||||||
|
timerDelay={DELAY}
|
||||||
|
value={SINGLE}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
await imagesDuring(src, DELAY * 3);
|
||||||
|
act(() => {
|
||||||
|
root.render(
|
||||||
|
<QrDisplay
|
||||||
|
timerDelay={DELAY}
|
||||||
|
value={MULTI}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
expect({ cycles: (await imagesDuring(src, DELAY * 6)).size > 1, test: 'single-to-multi' }).toEqual({ cycles: true, test: 'single-to-multi' });
|
||||||
|
|
||||||
|
act(() => {
|
||||||
|
root.unmount();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('stops its timer on unmount', async (): Promise<void> => {
|
||||||
|
const { el, root } = setup();
|
||||||
|
|
||||||
|
act(() => {
|
||||||
|
root.render(
|
||||||
|
<QrDisplay
|
||||||
|
timerDelay={DELAY}
|
||||||
|
value={MULTI}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
act(() => {
|
||||||
|
root.unmount();
|
||||||
|
});
|
||||||
|
// a timer left running would render into the unmounted root and throw
|
||||||
|
await sleep(DELAY * 3);
|
||||||
|
|
||||||
|
expect(el.querySelector('img')).toEqual(null);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -1,9 +1,8 @@
|
|||||||
// Copyright 2017-2026 @pezkuwi/react-qr authors & contributors
|
// Copyright 2017-2026 @pezkuwi/react-qr authors & contributors
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
import React, { useEffect, useMemo, useRef, useState } from 'react';
|
import React, { useEffect, useMemo, useState } from 'react';
|
||||||
|
|
||||||
import { objectSpread } from '@pezkuwi/util';
|
|
||||||
import { xxhashAsHex } from '@pezkuwi/util-crypto';
|
import { xxhashAsHex } from '@pezkuwi/util-crypto';
|
||||||
|
|
||||||
import { qrcode } from './qrcode.js';
|
import { qrcode } from './qrcode.js';
|
||||||
@@ -19,16 +18,11 @@ interface Props {
|
|||||||
value: Uint8Array;
|
value: Uint8Array;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface FrameState {
|
interface Shown {
|
||||||
frames: Uint8Array[];
|
|
||||||
frameIdx: number;
|
frameIdx: number;
|
||||||
image: string | null;
|
frames: Uint8Array[];
|
||||||
valueHash: string | null;
|
skipEncoding: boolean;
|
||||||
}
|
valueHash: string;
|
||||||
|
|
||||||
interface TimerState {
|
|
||||||
timerDelay: number;
|
|
||||||
timerId: ReturnType<typeof setTimeout> | null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const DEFAULT_FRAME_DELAY = 2750;
|
const DEFAULT_FRAME_DELAY = 2750;
|
||||||
@@ -45,75 +39,78 @@ function getDataUrl (value: Uint8Array): string {
|
|||||||
return qr.createDataURL(16, 0);
|
return qr.createDataURL(16, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
function Display ({ className = '', size, skipEncoding, style = {}, timerDelay = DEFAULT_FRAME_DELAY, value }: Props): React.ReactElement<Props> | null {
|
function encode (value: Uint8Array, skipEncoding: boolean, valueHash: string): Shown {
|
||||||
const [{ image }, setFrameState] = useState<FrameState>({ frameIdx: 0, frames: [], image: null, valueHash: null });
|
return {
|
||||||
const timerRef = useRef<TimerState>({ timerDelay, timerId: null });
|
frameIdx: 0,
|
||||||
|
frames: skipEncoding
|
||||||
|
? [value]
|
||||||
|
: createFrames(value),
|
||||||
|
skipEncoding,
|
||||||
|
valueHash
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function Display ({ className = '', size, skipEncoding = false, style = {}, timerDelay = DEFAULT_FRAME_DELAY, value }: Props): React.ReactElement<Props> | null {
|
||||||
|
// The frames follow the content of value (by hash), not the identity of the
|
||||||
|
// array, so a new array with the same bytes does not restart the display.
|
||||||
|
const valueHash = useMemo(() => xxhashAsHex(value), [value]);
|
||||||
|
const [shown, setShown] = useState<Shown>(() => encode(value, skipEncoding, valueHash));
|
||||||
|
|
||||||
|
// A new value (or encoding) starts again at its first frame. Adjusting state
|
||||||
|
// while rendering, as React documents for state that follows props, rather
|
||||||
|
// than in an effect, which renders the stale frame once more first.
|
||||||
|
if (shown.valueHash !== valueHash || shown.skipEncoding !== skipEncoding) {
|
||||||
|
setShown(encode(value, skipEncoding, valueHash));
|
||||||
|
}
|
||||||
|
|
||||||
const containerStyle = useMemo(
|
const containerStyle = useMemo(
|
||||||
() => createImgSize(size),
|
() => createImgSize(size),
|
||||||
[size]
|
[size]
|
||||||
);
|
);
|
||||||
|
|
||||||
// run on initial load to setup the global timer and provide and unsubscribe
|
// Frames are encoded on demand, not up front: for a large payload that
|
||||||
useEffect((): () => void => {
|
// keeps the first frame quick.
|
||||||
const nextFrame = () => setFrameState((state): FrameState => {
|
const image = useMemo(
|
||||||
// when we have a single frame, we only ever fire once
|
() => getDataUrl(shown.frames[shown.frameIdx]),
|
||||||
if (state.frames.length <= 1) {
|
[shown]
|
||||||
return state;
|
);
|
||||||
}
|
|
||||||
|
|
||||||
let frameIdx = state.frameIdx + 1;
|
// Step through the frames of the current value. Each full cycle slows the
|
||||||
|
// display a little. A single frame needs no timer; a new set of frames gets
|
||||||
|
// a new one, so the display animates whenever the value has several frames.
|
||||||
|
useEffect((): (() => void) | undefined => {
|
||||||
|
const frames = shown.frames;
|
||||||
|
|
||||||
// when we overflow, skip to the first and slightly increase the delay between frames
|
if (frames.length <= 1) {
|
||||||
if (frameIdx === state.frames.length) {
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
let frameIdx = 0;
|
||||||
|
let delay = timerDelay;
|
||||||
|
let timerId: ReturnType<typeof setTimeout>;
|
||||||
|
|
||||||
|
const nextFrame = (): void => {
|
||||||
|
frameIdx = frameIdx + 1;
|
||||||
|
|
||||||
|
if (frameIdx === frames.length) {
|
||||||
frameIdx = 0;
|
frameIdx = 0;
|
||||||
timerRef.current.timerDelay = timerRef.current.timerDelay + TIMER_INC;
|
delay = delay + TIMER_INC;
|
||||||
}
|
}
|
||||||
|
|
||||||
// only encode the frames on demand, not above as part of the
|
setShown((state) =>
|
||||||
// state derivation - in the case of large payloads, this should
|
state.frames === frames
|
||||||
// be slightly more responsive on initial load
|
? { ...state, frameIdx }
|
||||||
const newState = objectSpread<FrameState>({}, state, {
|
: state
|
||||||
frameIdx,
|
);
|
||||||
image: getDataUrl(state.frames[frameIdx])
|
timerId = setTimeout(nextFrame, delay);
|
||||||
});
|
};
|
||||||
|
|
||||||
// set the new timer last
|
timerId = setTimeout(nextFrame, delay);
|
||||||
timerRef.current.timerId = setTimeout(nextFrame, timerRef.current.timerDelay);
|
|
||||||
|
|
||||||
return newState;
|
|
||||||
});
|
|
||||||
|
|
||||||
timerRef.current.timerId = setTimeout(nextFrame, timerRef.current.timerDelay);
|
|
||||||
|
|
||||||
return (): void => {
|
return (): void => {
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
clearTimeout(timerId);
|
||||||
timerRef.current.timerId && clearTimeout(timerRef.current.timerId);
|
|
||||||
};
|
};
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
}, [shown.frames, timerDelay]);
|
||||||
}, []);
|
|
||||||
|
|
||||||
useEffect((): void => {
|
|
||||||
setFrameState((state): FrameState => {
|
|
||||||
const valueHash = xxhashAsHex(value);
|
|
||||||
|
|
||||||
if (valueHash === state.valueHash) {
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
|
|
||||||
const frames: Uint8Array[] = skipEncoding
|
|
||||||
? [value]
|
|
||||||
: createFrames(value);
|
|
||||||
|
|
||||||
// encode on demand
|
|
||||||
return {
|
|
||||||
frameIdx: 0,
|
|
||||||
frames,
|
|
||||||
image: getDataUrl(frames[0]),
|
|
||||||
valueHash
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}, [skipEncoding, value]);
|
|
||||||
|
|
||||||
if (!image) {
|
if (!image) {
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ function ScanAddress ({ className, isEthereum, onError, onScan, size, style }: P
|
|||||||
|
|
||||||
onScan({ content, genesisHash: genesisHash as HexString, isAddress, name: name?.length ? name.join(':') : undefined });
|
onScan({ content, genesisHash: genesisHash as HexString, isAddress, name: name?.length ? name.join(':') : undefined });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
onError && onError(error as Error);
|
onError?.(error as Error);
|
||||||
|
|
||||||
console.error('@pezkuwi/react-qr:QrScanAddress', (error as Error).message, data);
|
console.error('@pezkuwi/react-qr:QrScanAddress', (error as Error).message, data);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,8 @@
|
|||||||
"rootDir": "./src"
|
"rootDir": "./src"
|
||||||
},
|
},
|
||||||
"exclude": [
|
"exclude": [
|
||||||
"**/*.spec.ts"
|
"**/*.spec.ts",
|
||||||
|
"**/*.spec.tsx"
|
||||||
],
|
],
|
||||||
"references": [
|
"references": [
|
||||||
{ "path": "../ui-settings/tsconfig.build.json" }
|
{ "path": "../ui-settings/tsconfig.build.json" }
|
||||||
|
|||||||
@@ -8,7 +8,8 @@
|
|||||||
"noEmit": true
|
"noEmit": true
|
||||||
},
|
},
|
||||||
"include": [
|
"include": [
|
||||||
"**/*.spec.ts"
|
"**/*.spec.ts",
|
||||||
|
"**/*.spec.tsx"
|
||||||
],
|
],
|
||||||
"references": [
|
"references": [
|
||||||
{ "path": "../react-qr/tsconfig.build.json" }
|
{ "path": "../react-qr/tsconfig.build.json" }
|
||||||
|
|||||||
@@ -11,9 +11,7 @@ export interface KeyringSectionOption {
|
|||||||
|
|
||||||
export type KeyringSectionOptions = KeyringSectionOption[];
|
export type KeyringSectionOptions = KeyringSectionOption[];
|
||||||
|
|
||||||
export type KeyringOptions = {
|
export type KeyringOptions = Record<KeyringItemType | 'all' | 'allPlus' | 'recent' | 'testing', KeyringSectionOptions>;
|
||||||
[type in KeyringItemType | 'all' | 'allPlus' | 'recent' | 'testing']: KeyringSectionOptions
|
|
||||||
};
|
|
||||||
|
|
||||||
export type KeyringOption$Type = keyof KeyringOptions;
|
export type KeyringOption$Type = keyof KeyringOptions;
|
||||||
|
|
||||||
|
|||||||
@@ -18,11 +18,11 @@ export class BrowserStore implements KeyringStore {
|
|||||||
|
|
||||||
public remove (key: string, fn?: () => void): void {
|
public remove (key: string, fn?: () => void): void {
|
||||||
store.remove(key);
|
store.remove(key);
|
||||||
fn && fn();
|
fn?.();
|
||||||
}
|
}
|
||||||
|
|
||||||
public set (key: string, value: KeyringJson, fn?: () => void): void {
|
public set (key: string, value: KeyringJson, fn?: () => void): void {
|
||||||
store.set(key, value);
|
store.set(key, value);
|
||||||
fn && fn();
|
fn?.();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -64,12 +64,12 @@ export class FileStore implements KeyringStore {
|
|||||||
|
|
||||||
public remove (key: string, fn?: () => void): void {
|
public remove (key: string, fn?: () => void): void {
|
||||||
fs.unlinkSync(this._getPath(key));
|
fs.unlinkSync(this._getPath(key));
|
||||||
fn && fn();
|
fn?.();
|
||||||
}
|
}
|
||||||
|
|
||||||
public set (key: string, value: KeyringJson, fn?: () => void): void {
|
public set (key: string, value: KeyringJson, fn?: () => void): void {
|
||||||
fs.writeFileSync(this._getPath(key), Buffer.from(JSON.stringify(value), 'utf-8'));
|
fs.writeFileSync(this._getPath(key), Buffer.from(JSON.stringify(value), 'utf-8'));
|
||||||
fn && fn();
|
fn?.();
|
||||||
}
|
}
|
||||||
|
|
||||||
private _getPath (key: string): string {
|
private _getPath (key: string): string {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// Copyright 2017-2026 @pezkuwi/ui-settings authors & contributors
|
// Copyright 2017-2026 @pezkuwi/ui-settings authors & contributors
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
import type { Endpoint, EndpointType, Option, SettingsStruct } from './types.js';
|
import type { Endpoint, Option, SettingsStruct } from './types.js';
|
||||||
|
|
||||||
import { EventEmitter } from 'eventemitter3';
|
import { EventEmitter } from 'eventemitter3';
|
||||||
import store from 'store';
|
import store from 'store';
|
||||||
@@ -60,7 +60,7 @@ export class Settings implements SettingsStruct {
|
|||||||
|
|
||||||
// will become deprecated for supporting substrate connect light clients. apiType structure should be used instead
|
// will become deprecated for supporting substrate connect light clients. apiType structure should be used instead
|
||||||
this.#apiUrl = (typeof settings.apiUrl === 'string' && settings.apiUrl) || (hasProcess && process.env?.['WS_URL']) || (ENDPOINT_DEFAULT.value as string);
|
this.#apiUrl = (typeof settings.apiUrl === 'string' && settings.apiUrl) || (hasProcess && process.env?.['WS_URL']) || (ENDPOINT_DEFAULT.value as string);
|
||||||
this.#apiType = { param: this.#apiUrl, type: 'json-rpc' as EndpointType };
|
this.#apiType = { param: this.#apiUrl, type: 'json-rpc' };
|
||||||
this.#camera = withDefault(CAMERA, settings.camera, CAMERA_DEFAULT);
|
this.#camera = withDefault(CAMERA, settings.camera, CAMERA_DEFAULT);
|
||||||
this.#ledgerApp = withDefault(LEDGER_APP, settings.ledgerApp, LEDGER_APP_DEFAULT);
|
this.#ledgerApp = withDefault(LEDGER_APP, settings.ledgerApp, LEDGER_APP_DEFAULT);
|
||||||
this.#ledgerConn = withDefault(LEDGER_CONN, settings.ledgerConn, LEDGER_CONN_DEFAULT);
|
this.#ledgerConn = withDefault(LEDGER_CONN, settings.ledgerConn, LEDGER_CONN_DEFAULT);
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ describe('identicon', (): void => {
|
|||||||
it('generates a basic [0,..,0] identicon', (): void => {
|
it('generates a basic [0,..,0] identicon', (): void => {
|
||||||
expect(
|
expect(
|
||||||
xmlserializer.serializeToString(
|
xmlserializer.serializeToString(
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument,@typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
beachballIcon(new Uint8Array(32), { isAlternative: false, size: 256 }) as any
|
beachballIcon(new Uint8Array(32), { isAlternative: false, size: 256 }) as any
|
||||||
)
|
)
|
||||||
).toEqual(
|
).toEqual(
|
||||||
@@ -24,7 +24,7 @@ describe('identicon', (): void => {
|
|||||||
it('allows overrides', (): void => {
|
it('allows overrides', (): void => {
|
||||||
expect(
|
expect(
|
||||||
xmlserializer.serializeToString(
|
xmlserializer.serializeToString(
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument,@typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
beachballIcon(new Uint8Array(32), { isAlternative: false, size: 100 }, 'testClass', { display: 'block' }) as any
|
beachballIcon(new Uint8Array(32), { isAlternative: false, size: 100 }, 'testClass', { display: 'block' }) as any
|
||||||
)
|
)
|
||||||
).toEqual(
|
).toEqual(
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ describe('circle', (): void => {
|
|||||||
it('creates a circle shape', (): void => {
|
it('creates a circle shape', (): void => {
|
||||||
expect(
|
expect(
|
||||||
xmlserializer.serializeToString(
|
xmlserializer.serializeToString(
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument,@typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
circle(seeder(), 'blue', 50, 2) as any
|
circle(seeder(), 'blue', 50, 2) as any
|
||||||
)
|
)
|
||||||
).toEqual('<circle xmlns="http://www.w3.org/2000/svg" cx="25" cy="32.5" r="15" fill="blue"/>');
|
).toEqual('<circle xmlns="http://www.w3.org/2000/svg" cx="25" cy="32.5" r="15" fill="blue"/>');
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ describe('circle', (): void => {
|
|||||||
it('creates a basic SVG circle element', (): void => {
|
it('creates a basic SVG circle element', (): void => {
|
||||||
expect(
|
expect(
|
||||||
xs.serializeToString(
|
xs.serializeToString(
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument,@typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
circle(123, 12, 34) as any
|
circle(123, 12, 34) as any
|
||||||
)
|
)
|
||||||
).toEqual('<circle xmlns="http://www.w3.org/2000/svg" cx="12" cy="34" r="123"/>');
|
).toEqual('<circle xmlns="http://www.w3.org/2000/svg" cx="12" cy="34" r="123"/>');
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ describe('element', (): void => {
|
|||||||
it('creates a basic SVG element', (): void => {
|
it('creates a basic SVG element', (): void => {
|
||||||
expect(
|
expect(
|
||||||
xs.serializeToString(
|
xs.serializeToString(
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument,@typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
element(123) as any
|
element(123) as any
|
||||||
)
|
)
|
||||||
).toEqual('<svg xmlns="http://www.w3.org/2000/svg" x="0" y="0" width="123" height="123"/>');
|
).toEqual('<svg xmlns="http://www.w3.org/2000/svg" x="0" y="0" width="123" height="123"/>');
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ describe('rect', (): void => {
|
|||||||
it('creates a basic SVG rect element', (): void => {
|
it('creates a basic SVG rect element', (): void => {
|
||||||
expect(
|
expect(
|
||||||
xs.serializeToString(
|
xs.serializeToString(
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument,@typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
rect(123) as any
|
rect(123) as any
|
||||||
)
|
)
|
||||||
).toEqual('<rect xmlns="http://www.w3.org/2000/svg" x="0" y="0" width="123" height="123" rx="7.6875" ry="7.6875"/>');
|
).toEqual('<rect xmlns="http://www.w3.org/2000/svg" x="0" y="0" width="123" height="123" rx="7.6875" ry="7.6875"/>');
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ describe('svg', (): void => {
|
|||||||
it('creates a basic SVG element', (): void => {
|
it('creates a basic SVG element', (): void => {
|
||||||
expect(
|
expect(
|
||||||
xs.serializeToString(
|
xs.serializeToString(
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument,@typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
svg('rect') as any
|
svg('rect') as any
|
||||||
)
|
)
|
||||||
).toEqual('<rect xmlns="http://www.w3.org/2000/svg"/>');
|
).toEqual('<rect xmlns="http://www.w3.org/2000/svg"/>');
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ function resolvePublicKey (value: string | Uint8Array, prefix?: Prefix): string
|
|||||||
}
|
}
|
||||||
|
|
||||||
return isU8a(value) || isHex(value)
|
return isU8a(value) || isHex(value)
|
||||||
? encodeAddress(value as string, prefix)
|
? encodeAddress(value, prefix)
|
||||||
: value;
|
: value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user