Move to @pezkuwi/dev 0.86 (eslint 10 toolchain)

- @pezkuwi/dev, dev-test, dev-ts ^0.86.3 in the root and in every
  workspace package (they still asked for 0.84.3)
- tsconfig.base target ES2022, the @pezkuwi/dev default; it carries
  the ErrorOptions type for `cause`
- rethrown errors carry the original as `cause`; rejections are
  normalised to Error
- page/messaging: the typed subscriber is called directly, not as
  `Function`
- chrome mock: constant results through Promise.resolve
- useLedger: drop a construction every branch below repeated
- InputWithLabel: onKeyDown instead of the deprecated onKeyPress
- Account: toggleActions + 1 instead of a pre-increment of a parameter
- optional chains where a guard tested the same value
- specs: mount<React.Component> so the wrappers are not `any`-typed
- AccountsStore.set keeps its async override of KeyringStore.set:
  BaseStore.set handles its own failure, so it never rejects
- extension-chains keeps its ChainProperties assertion: the package's
  own build does not load the type augmentation
- the existing React Compiler findings (37, react-hooks rules only)
  are recorded in eslint-suppressions.json; a new one fails lint
This commit is contained in:
Satoshi Qazi Muhammed authored and SatoshiQaziMuhammed committed 2026-10-09 16:32:46 +04:00
1 parent 0321454dc7
commit 9d769676e4
58 files changed
+2795 -3355

No files matched your search

@@ -25,7 +25,7 @@ const { configure, mount } = enzyme;
// ...jest.requireActual('../../messaging')
// }));
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-call
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
configure({ adapter: new Adapter() });
jest.spyOn(messaging, 'getAllMetadata').mockImplementation(() => Promise.resolve([]));
@@ -45,7 +45,7 @@ function Account ({ address, className, genesisHash, isExternal, isHardware, isH
? selectedAccounts.filter((account) => account !== address)
: [...selectedAccounts, address];
setSelectedAccounts && setSelectedAccounts(newList);
setSelectedAccounts?.(newList);
}, [address, selectedAccounts, setSelectedAccounts]);
const _onChangeGenesis = useCallback(
@@ -57,7 +57,7 @@ function Account ({ address, className, genesisHash, isExternal, isHardware, isH
);
const _toggleEdit = useCallback(
(): void => setEditing(({ toggleActions }) => ({ isEditing: !isEditing, toggleActions: ++toggleActions })),
(): void => setEditing(({ toggleActions }) => ({ isEditing: !isEditing, toggleActions: toggleActions + 1 })),
[isEditing]
);
@@ -4,8 +4,8 @@
// We _could_ reformat, but just keep it as-is, since this is actually
// externally generated and not really user-editable
/* eslint-disable react/jsx-sort-props */
/* eslint-disable react/jsx-max-props-per-line */
/* eslint-disable @stylistic/jsx-sort-props */
/* eslint-disable @stylistic/jsx-max-props-per-line */
import React from 'react';
@@ -15,7 +15,7 @@ interface Props {
}
function AccountManagement ({ className }: Props): React.ReactElement<Props> {
const { url } = useParams<{url: string}>();
const { url } = useParams<{ url: string }>();
const decodedUrl = decodeURIComponent(url);
const { selectedAccounts = [], setSelectedAccounts } = useContext(AccountContext);
const { t } = useTranslation();
@@ -28,7 +28,7 @@ function AccountManagement ({ className }: Props): React.ReactElement<Props> {
return;
}
setSelectedAccounts && setSelectedAccounts(list[decodedUrl].authorizedAccounts);
setSelectedAccounts?.(list[decodedUrl].authorizedAccounts);
})
.catch(console.error);
}, [setSelectedAccounts, decodedUrl]);
@@ -20,7 +20,7 @@ import Request from './Request.js';
const { configure, mount } = enzyme;
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-call
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
configure({ adapter: new Adapter() });
const oneRequest = [{ id: '1', request: { origin: '???' }, url: 'http://pezkuwichain.io' }];
@@ -30,7 +30,7 @@ function Request ({ authId, className, request: { origin }, url }: Props): React
.filter(({ isDefaultAuthSelected }) => !!isDefaultAuthSelected)
.map(({ address }) => address);
setSelectedAccounts && setSelectedAccounts(defaultAccountSelection);
setSelectedAccounts?.(defaultAccountSelection);
}, [accounts, setSelectedAccounts]);
const _onApprove = useCallback(
@@ -29,7 +29,7 @@ const { configure, mount } = enzyme;
// For this file, there are a lot of them
/* eslint-disable @typescript-eslint/no-unsafe-argument */
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-call
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
configure({ adapter: new Adapter() });
describe('Create Account', () => {
@@ -38,12 +38,11 @@ function CreateAccount ({ className }: Props): React.ReactElement {
setSeed(seed);
})
.catch(console.error);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
useEffect((): void => {
if (seed) {
const type = chain && chain.definition.chainType === 'ethereum'
const type = chain?.definition.chainType === 'ethereum'
? 'ethereum'
: DEFAULT_TYPE;
@@ -5,7 +5,7 @@ import '@pezkuwi/extension-mocks/chrome';
import type { ReactWrapper } from 'enzyme';
import type * as _ from '@pezkuwi/dev-test/globals.d.ts';
import type { AccountJson, ResponseDeriveValidate } from '@pezkuwi/extension-base/background/types';
import type { AccountJson } from '@pezkuwi/extension-base/background/types';
import Adapter from '@wojtekmaj/enzyme-adapter-react-17';
import enzyme from 'enzyme';
@@ -32,7 +32,7 @@ const { configure, mount } = enzyme;
// For this file, there are a lot of them
/* eslint-disable @typescript-eslint/no-unsafe-argument */
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-call
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
configure({ adapter: new Adapter() });
const parentPassword = 'pass';
@@ -57,7 +57,7 @@ describe('Derive', () => {
}> => {
const onActionStub = jest.fn();
const wrapper = mount(
const wrapper = mount<React.Component>(
<MemoryRouter initialEntries={ [`/account/derive/${accounts[account].address}`] }>
<ActionContext.Provider value={onActionStub}>
<AccountContext.Provider
@@ -110,7 +110,7 @@ describe('Derive', () => {
throw new Error('wrong suri');
}
return { address: derivedAddress, suri: defaultDerivation } as ResponseDeriveValidate;
return { address: derivedAddress, suri: defaultDerivation };
});
it('Button is disabled and password field visible, path field is hidden', () => {
@@ -216,7 +216,7 @@ describe('Derive', () => {
expect(button.prop('disabled')).toBe(true);
expect(wrapper.find('.warning-message')).toHaveLength(1);
// eslint-disable-next-line quotes
// eslint-disable-next-line @stylistic/quotes
expect(wrapper.find('.warning-message').first().text()).toEqual("`///password` not supported for derivation");
});
@@ -27,7 +27,7 @@ const { configure, mount } = enzyme;
// ...jest.requireActual('../messaging')
// }));
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-call
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
configure({ adapter: new Adapter() });
describe('Export component', () => {
+4 -4
View File
@@ -15,7 +15,7 @@ import { styled } from '../styled.js';
const MIN_LENGTH = 6;
interface Props extends RouteComponentProps<{address: string}> {
interface Props extends RouteComponentProps<{ address: string }> {
className?: string;
}
@@ -35,8 +35,8 @@ function Export ({ className, match: { params: { address } } }: Props): React.Re
(password: string) => {
setPass(password);
setError('');
}
, []);
},
[]);
const _onExportButtonClick = useCallback(
(): void => {
@@ -46,7 +46,7 @@ function Export ({ className, match: { params: { address } } }: Props): React.Re
.then(({ exportedJson }) => {
const blob = new Blob([JSON.stringify(exportedJson)], { type: 'application/json; charset=utf-8' });
// eslint-disable-next-line deprecation/deprecation
// eslint-disable-next-line @typescript-eslint/no-deprecated
fileSaver.saveAs(blob, `${address}.json`);
onAction('/');
@@ -36,8 +36,8 @@ function ExportAll ({ className }: Props): React.ReactElement<Props> {
(password: string) => {
setPass(password);
setError('');
}
, []);
},
[]);
const _onExportAllButtonClick = useCallback(
(): void => {
@@ -47,7 +47,7 @@ function ExportAll ({ className }: Props): React.ReactElement<Props> {
.then(({ exportedJson }) => {
const blob = new Blob([JSON.stringify(exportedJson)], { type: 'application/json; charset=utf-8' });
// eslint-disable-next-line deprecation/deprecation
// eslint-disable-next-line @typescript-eslint/no-deprecated
fileSaver.saveAs(blob, `batch_exported_account_${Date.now()}.json`);
onAction('/');
@@ -49,7 +49,7 @@ interface QrScanAddressProps {
// ...jest.requireActual('../messaging')
// }));
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-call
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
configure({ adapter: new Adapter() });
const typeName = async (wrapper: ReactWrapper, value: string) => {
@@ -77,7 +77,6 @@ describe('ImportQr component', () => {
</MemoryRouter>
);
// eslint-disable-next-line @typescript-eslint/no-floating-promises
act(() => {
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
(wrapper.find('QrScanAddress').first().prop('onScan') as unknown as QrScanAddressProps['onScan'])(mockedAccount);
@@ -38,7 +38,7 @@ const account = {
// For this file, there are a lot of them
/* eslint-disable @typescript-eslint/no-unsafe-argument */
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-call
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
configure({ adapter: new Adapter() });
jest.spyOn(messaging, 'getAllMetadata').mockImplementation(() => Promise.resolve([]));
@@ -36,7 +36,7 @@ function ImportSeed (): React.ReactElement {
useEffect((): void => {
setType(
chain && chain.definition.chainType === 'ethereum'
chain?.definition.chainType === 'ethereum'
? 'ethereum'
: DEFAULT_TYPE
);
@@ -120,7 +120,7 @@ function Extrinsic ({ className, payload, request: { blockNumber, genesisHash, m
const chain = useMetadata(genesisHash);
const specVersion = useRef(bnToBn(hexSpec)).current;
const decoded = useMemo(
() => chain && chain.hasMetadata
() => chain?.hasMetadata
? decodeMethod(method, chain, specVersion)
: { args: null, method: null },
[method, chain, specVersion]
@@ -1,7 +1,7 @@
// Copyright 2019-2026 @pezkuwi/extension-ui authors & contributors
// SPDX-License-Identifier: Apache-2.0
/* eslint-disable deprecation/deprecation */
/* eslint-disable @typescript-eslint/no-deprecated */
import type { Chain } from '@pezkuwi/extension-chains/types';
import type { Ledger, LedgerGeneric } from '@pezkuwi/hw-ledger';
@@ -41,7 +41,7 @@ const { configure, mount } = enzyme;
// For this file, there are a lot of them
/* eslint-disable @typescript-eslint/no-unsafe-argument */
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-call
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
configure({ adapter: new Adapter() });
describe('Signing requests', () => {
@@ -345,7 +345,6 @@ describe('Signing requests', () => {
wrapper.find('FontAwesomeIcon.arrowRight').simulate('click');
await act(flushAllPromises);
// eslint-disable-next-line @typescript-eslint/no-floating-promises
act(() => {
emitter.emit('request', [signRequests[0]]);
});
+4
View File
@@ -3,20 +3,24 @@
declare module '*.svg' {
const url: string;
export default url;
}
declare module '*.png' {
const url: string;
export default url;
}
declare module '*.woff' {
const url: string;
export default url;
}
declare module '*.woff2' {
const url: string;
export default url;
}
@@ -20,7 +20,7 @@ import { AccountNamePasswordCreation, Input, InputWithLabel, NextStepButton } fr
const { configure, mount } = enzyme;
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-call
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
configure({ adapter: new Adapter() });
const account = {
@@ -40,7 +40,7 @@ function AccountNamePasswordCreation ({ buttonLabel, isBusy, onBackClick, onCrea
const _onPasswordChange = useCallback(
(password: string | null) => {
onPasswordChange && onPasswordChange(password || '');
onPasswordChange?.(password || '');
setPassword(password);
},
[onPasswordChange]
@@ -50,7 +50,7 @@ function AccountNamePasswordCreation ({ buttonLabel, isBusy, onBackClick, onCrea
() => {
_onNameChange(null);
setPassword(null);
onBackClick && onBackClick();
onBackClick?.();
},
[_onNameChange, onBackClick]
);
@@ -38,7 +38,7 @@ const { configure, mount } = enzyme;
// ...jest.requireActual('../MetadataCache')
// }));
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-call
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
configure({ adapter: new Adapter() });
interface AccountTestJson extends AccountJson {
@@ -121,7 +121,7 @@ const mountComponent = async (addressComponentProps: AddressComponentProps, cont
const actionStub = jest.fn();
const { actions = actionStub } = addressComponentProps;
const wrapper = mount(
const wrapper = mount<React.Component>(
<AccountContext.Provider
value={{
accounts: contextAccounts,
@@ -25,12 +25,12 @@ function Checkbox ({ checked, className, indeterminate, label, onChange, onClick
}, [indeterminate]);
const _onChange = useCallback(
(event: React.ChangeEvent<HTMLInputElement>) => onChange && onChange(event.target.checked),
(event: React.ChangeEvent<HTMLInputElement>) => onChange?.(event.target.checked),
[onChange]
);
const _onClick = useCallback(
() => onClick && onClick(),
() => onClick?.(),
[onClick]
);
@@ -29,7 +29,7 @@ interface Props {
function Dropdown ({ className, defaultValue, isDisabled, isFocussed, label, onBlur, onChange, options, value }: Props): React.ReactElement<Props> {
const _onChange = useCallback(
({ target: { value } }: React.ChangeEvent<HTMLSelectElement>) =>
onChange && onChange(value.trim()),
onChange?.(value.trim()),
[onChange]
);
@@ -77,7 +77,7 @@ function InputFile ({ accept, className = '', clearContent, convertHex, isDisabl
const name = file.name;
const data = convertResult(target.result as ArrayBuffer, convertHex);
onChange && onChange(data, name);
onChange?.(data, name);
dropRef && setFile({
name,
size: data.length
@@ -25,7 +25,7 @@ function InputFilter ({ className, onChange, placeholder, value, withReset = fal
const onResetFilter = useCallback(() => {
onChange('');
inputRef?.current && inputRef.current.select();
inputRef?.current?.select();
}, [onChange]);
return (
@@ -48,7 +48,7 @@ function InputWithLabel ({ className, defaultValue, disabled, isError, isFocused
const _onChange = useCallback(
({ target: { value } }: React.ChangeEvent<HTMLInputElement>): void => {
onChange && onChange(value);
onChange?.(value);
},
[onChange]
);
@@ -67,7 +67,7 @@ function InputWithLabel ({ className, defaultValue, disabled, isError, isFocused
onBlur={onBlur}
onChange={_onChange}
onFocus={onFocus}
onKeyPress={_checkKey}
onKeyDown={_checkKey}
placeholder={placeholder}
readOnly={isReadOnly}
spellCheck={false}
@@ -20,7 +20,7 @@ interface Props {
export default function TextAreaWithLabel ({ className, isError, isFocused, isReadOnly, label, onChange, rowsCount, value }: Props): React.ReactElement<Props> {
const _onChange = useCallback(
({ target: { value } }: React.ChangeEvent<HTMLTextAreaElement>): void => {
onChange && onChange(value);
onChange?.(value);
},
[onChange]
);
@@ -23,7 +23,7 @@ type Props<T extends BasicProps> = T & {
defaultValue?: string;
onValidatedChange: (value: string | null) => void;
validator: Validator<string>;
}
};
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 || '');
@@ -19,6 +19,6 @@ const MetadataReqContext = React.createContext<MetadataRequest[]>([]);
const SettingsContext = React.createContext<SettingsStruct>(settings.get());
const SigningReqContext = React.createContext<SigningRequest[]>([]);
const ThemeSwitchContext = React.createContext<(theme: Theme) => void>(noop);
const ToastContext = React.createContext<({show: (message: string) => void})>({ show: noop });
const ToastContext = React.createContext<({ show: (message: string) => void })>({ show: noop });
export { AccountContext, ActionContext, AuthorizeReqContext, MediaContext, MetadataReqContext, SettingsContext, SigningReqContext, ThemeSwitchContext, ToastContext };
@@ -14,7 +14,7 @@ export function chooseTheme (): Theme {
: 'light';
}
return window.matchMedia && window.matchMedia('(prefers-color-scheme: light)').matches
return window.matchMedia?.('(prefers-color-scheme: light)').matches
? 'light'
: 'dark';
}
+2 -6
View File
@@ -3,7 +3,7 @@
// This is to ensure the legacy `class Ledger` doesn't throw linting errors.
//
/* eslint-disable deprecation/deprecation */
/* eslint-disable @typescript-eslint/no-deprecated */
import type { Network } from '@pezkuwi/networks/types';
import type { HexString } from '@pezkuwi/util/types';
@@ -50,7 +50,7 @@ function getState (): StateBase {
}
function retrieveLedger (genesis: string): LedgerGeneric | Ledger {
let ledger: LedgerGeneric | Ledger | null = null;
let ledger: LedgerGeneric | Ledger;
const currApp = settings.get().ledgerApp;
@@ -64,10 +64,6 @@ function retrieveLedger (genesis: string): LedgerGeneric | Ledger {
assert(def.slip44, 'Slip44 is not available for this network, please report an issue to update this chains slip44');
// All chains use the `slip44` from polkadot in their derivation path in ledger.
// This interface is specific to the underlying PolkadotGenericApp.
ledger = new LedgerGeneric('webusb', def.network, knownLedger['polkadot']);
if (currApp === 'generic') {
// All chains use the `slip44` from polkadot in their derivation path in ledger.
// This interface is specific to the underlying PolkadotGenericApp.
@@ -5,7 +5,7 @@ import type { RefObject } from 'react';
import { useCallback, useEffect } from 'react';
export default function useOutsideClick (refs: RefObject<HTMLDivElement|null>[], callback: () => void): void {
export default function useOutsideClick (refs: RefObject<HTMLDivElement | null>[], callback: () => void): void {
const handleClick = useCallback((e: MouseEvent): void => {
refs.every(({ current }) =>
current &&
+1 -1
View File
@@ -5,6 +5,6 @@ import { useContext } from 'react';
import { ToastContext } from '../components/contexts.js';
export default function useToast (): {show: (message: string) => void} {
export default function useToast (): { show: (message: string) => void } {
return useContext(ToastContext);
}
+6 -6
View File
@@ -49,8 +49,7 @@ function onPortMessageHandler (data: Message['data']): void {
}
if (data.subscription) {
// eslint-disable-next-line @typescript-eslint/ban-types
(handler.subscriber as Function)(data.subscription);
handler.subscriber?.(data.subscription);
} else if (data.error) {
handler.reject(new Error(data.error));
} else {
@@ -68,9 +67,10 @@ const portConfig = {
portName: PORT_EXTENSION
};
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 MessageTypesWithSubscriptions>(message: TMessageType, request: RequestTypes[TMessageType], subscriber: (data: SubscriptionMessageTypes[TMessageType]) => void): 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 MessageTypesWithSubscriptions> (message: TMessageType, request: RequestTypes[TMessageType], subscriber: (data: SubscriptionMessageTypes[TMessageType]) => void): Promise<ResponseTypes[TMessageType]>;
function sendMessage<TMessageType extends MessageTypes> (message: TMessageType, request?: RequestTypes[TMessageType], subscriber?: (data: unknown) => void): Promise<ResponseTypes[TMessageType]> {
return new Promise((resolve, reject): void => {
const id = getId();
@@ -82,7 +82,7 @@ function sendMessage<TMessageType extends MessageTypes> (message: TMessageType,
port = connectedPort;
}).catch((error) => {
console.error(`Failed to send message: ${(error as Error).message}`);
reject(error);
reject(error instanceof Error ? error : new Error(String(error)));
});
});
}
@@ -30,12 +30,12 @@ function AccountSelection ({ className, origin, showHidden = false, url, withWar
const allDisplayedAddresses = useMemo(
() => showHidden
? accounts.map(({ address }) => address)
: allVisibleAccounts.map(({ address }) => address)
, [accounts, allVisibleAccounts, showHidden]
: allVisibleAccounts.map(({ address }) => address),
[accounts, allVisibleAccounts, showHidden]
);
const areAllAccountsSelected = useMemo(
() => selectedAccounts.length === allDisplayedAddresses.length
, [allDisplayedAddresses.length, selectedAccounts.length]
() => selectedAccounts.length === allDisplayedAddresses.length,
[allDisplayedAddresses.length, selectedAccounts.length]
);
useEffect(() => {
@@ -54,12 +54,12 @@ function AccountSelection ({ className, origin, showHidden = false, url, withWar
const _onSelectAllToggle = useCallback(() => {
if (areAllAccountsSelected) {
setSelectedAccounts && setSelectedAccounts([]);
setSelectedAccounts?.([]);
return;
}
setSelectedAccounts && setSelectedAccounts(allDisplayedAddresses);
setSelectedAccounts?.(allDisplayedAddresses);
}, [allDisplayedAddresses, areAllAccountsSelected, setSelectedAccounts]
);
@@ -16,7 +16,7 @@ import Settings from './MenuSettings.js';
const { configure, mount } = enzyme;
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-call
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
configure({ adapter: new Adapter() });
describe('Header component', () => {
@@ -39,8 +39,8 @@ function Header ({ children, className = '', onFilter, showAdd, showBackArrow, s
const addMenuRef = useRef<HTMLDivElement>(null);
const setIconRef = useRef(null);
const setMenuRef = useRef<HTMLDivElement>(null);
const isConnected = useMemo(() => connectedTabsUrl.length >= 1
, [connectedTabsUrl]);
const isConnected = useMemo(() => connectedTabsUrl.length >= 1,
[connectedTabsUrl]);
const onAction = useContext(ActionContext);
useEffect(() => {
@@ -74,7 +74,7 @@ function Header ({ children, className = '', onFilter, showAdd, showBackArrow, s
const _onChangeFilter = useCallback(
(filter: string) => {
setFilter(filter);
onFilter && onFilter(filter);
onFilter?.(filter);
},
[onFilter]
);
@@ -91,8 +91,8 @@ function Header ({ children, className = '', onFilter, showAdd, showBackArrow, s
);
const _onBackArrowClick = useCallback(
() => onAction('../index.js')
, [onAction]);
() => onAction('../index.js'),
[onAction]);
return (
<div className={`${className} ${smallMargin ? 'smallMargin' : ''}`}>