Rework (some) component styled injection (#8795)

* Rework (some) component styled injection

* Small build fixes

* Additional build fixes

* Additional

* Fixes

* Remove unused SelectedDrag

* Remover unneeded props passing

* Fix build

* Remove unneeded inline-block
This commit is contained in:
Jaco 2023-01-14 15:22:42 +02:00 committed by GitHub
parent bdaeeb661d
commit e63eeb506c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
46 changed files with 256 additions and 244 deletions

View File

@ -473,7 +473,7 @@ function Account ({ account: { address, meta }, className = '', delegation, filt
/>
<td className='address all relative'>
<AddressSmall
parentAddress={meta.parentAddress}
parentAddress={meta.parentAddress as string}
value={address}
withShortAddress
/>

View File

@ -19,7 +19,7 @@ function JudgementTag ({ judgement: { judgementName, registrars } }: Props): Rea
return (
<Popup
closeOnScroll
position='center'
position='middle'
value={
<Menu>
{registrars.map((registrar) => registrar && (

View File

@ -255,7 +255,7 @@ function Create ({ className = '', onClose, onStatusChange, seed: propsSeed, typ
fullLength
isEditableName={false}
noDefaultNameOpacity
value={isSeedValid ? address : ''}
value={(isSeedValid && address) || null}
/>
</Modal.Columns>
{step === 1 && <>

View File

@ -182,7 +182,6 @@ function Multisig ({ className = '', onClose, onStatusChange }: Props): React.Re
availableLabel={t<string>('available signatories')}
maxCount={MAX_SIGNATORIES}
onChange={_onChangeAddressMulti}
value={signatories}
valueLabel={t<string>('selected signatories')}
/>
</Modal.Columns>

View File

@ -60,7 +60,6 @@ function RecoverSetup ({ address, className = '', onClose }: Props): React.React
availableLabel={t<string>('available social recovery helpers')}
maxCount={MAX_HELPERS}
onChange={setHelpers}
value={helpers}
valueLabel={t<string>('trusted social recovery helpers')}
/>
</Modal.Columns>

View File

@ -17,7 +17,7 @@ interface Props {
function Asset ({ className, value: { details, id, isIssuerMe, metadata } }: Props): React.ReactElement<Props> {
const format = useMemo(
() => metadata
(): [number, string] => metadata
? [metadata.decimals.toNumber(), metadata.symbol.toUtf8()]
: [0, '---'],
[metadata]

View File

@ -5,7 +5,7 @@ import type { TFunction } from 'i18next';
import type { TabItem } from '@polkadot/react-components/Tabs/types';
import type { KeyedEvent } from '@polkadot/react-hooks/ctx/types';
import React, { useRef, useState } from 'react';
import React, { useMemo, useRef } from 'react';
import { Route, Switch } from 'react-router';
import { Tabs } from '@polkadot/react-components';
@ -78,7 +78,11 @@ function ExplorerApp ({ basePath, className }: Props): React.ReactElement<Props>
const { eventCount, events } = useBlockEvents();
const itemsRef = useRef(createItemsRef(t));
const pathRef = useRef(createPathRef(basePath));
const hidden = useState(() => isFunction(api.query.babe?.authorities) ? [] : ['forks']);
const hidden = useMemo<string[]>(
() => isFunction(api.query.babe?.authorities) ? [] : ['forks'],
[api]
);
return (
<main className={className}>

View File

@ -53,7 +53,7 @@ function Summary ({ activeTotal, className, isDisabled }: Props): React.ReactEle
<CardSummary
label={t<string>('intake')}
progress={{
total: api.consts.gilt.intakePeriod,
total: api.consts.gilt.intakePeriod as u128,
value: bestNumber.mod(api.consts.gilt.intakePeriod as u128),
withTime: true
}}

View File

@ -65,8 +65,8 @@ function Bag ({ bagLower, bagUpper, info, nodesOwn }: Props): React.ReactElement
<td className='number' />
<td className='number'><FormatBalance value={bagUpper} /></td>
<td className='number'><FormatBalance value={bagLower} /></td>
<td className='address'>{info.head.isSome && <AddressMini value={info.head} />}</td>
<td className='address'>{info.tail.isSome && <AddressMini value={info.tail} />}</td>
<td className='address'>{info.head.isSome && <AddressMini value={info.head.unwrap()} />}</td>
<td className='address'>{info.tail.isSome && <AddressMini value={info.tail.unwrap()} />}</td>
<td className='address'>
{nodesOwn?.map(({ stashId }) => (
<Stash

View File

@ -125,19 +125,19 @@ function Pool ({ className = '', members, ownAccounts, params, poolId }: Props):
{info.bonded.roles.root.isSome && (
<div className='label-column-right'>
<div className='label'>{t('root')}</div>
<div className='inline-balance'><AddressMini value={info.bonded.roles.root} /></div>
<div className='inline-balance'><AddressMini value={info.bonded.roles.root.unwrap()} /></div>
</div>
)}
{info.bonded.roles.nominator.isSome && (
<div className='label-column-right'>
<div className='label'>{t('nominator')}</div>
<div className='inline-balance'><AddressMini value={info.bonded.roles.nominator} /></div>
<div className='inline-balance'><AddressMini value={info.bonded.roles.nominator.unwrap()} /></div>
</div>
)}
{info.bonded.roles.stateToggler.isSome && (
<div className='label-column-right'>
<div className='label'>{t('toggler')}</div>
<div className='inline-balance'><AddressMini value={info.bonded.roles.stateToggler} /></div>
<div className='inline-balance'><AddressMini value={info.bonded.roles.stateToggler.unwrap()} /></div>
</div>
)}
</td>

View File

@ -24,7 +24,7 @@ interface Props {
onClick?: () => void;
override?: React.ReactNode;
// this is used by app-account/addresses to toggle editing
toggle?: boolean;
toggle?: unknown;
value: AccountId | AccountIndex | Address | string | Uint8Array | null | undefined;
withSidebar?: boolean;
}
@ -209,7 +209,7 @@ function AccountName ({ children, className = '', defaultName, label, onClick, o
);
return (
<span
<StyledSpan
className={`ui--AccountName${withSidebar ? ' withSidebar' : ''} ${className}`}
data-testid='account-name'
onClick={
@ -219,11 +219,11 @@ function AccountName ({ children, className = '', defaultName, label, onClick, o
}
>
{label || ''}{override || name}{children}
</span>
</StyledSpan>
);
}
export default React.memo(styled(AccountName)`
const StyledSpan = styled.span`
border: 1px dotted transparent;
line-height: 1;
vertical-align: middle;
@ -267,4 +267,6 @@ export default React.memo(styled(AccountName)`
}
}
}
`);
`;
export default React.memo(AccountName);

View File

@ -45,7 +45,7 @@ function AddressMini ({ balance, bonded, children, className = '', iconInfo, isH
}
return (
<div className={`ui--AddressMini${isHighlight ? ' isHighlight' : ''}${isPadded ? ' padded' : ''}${withShrink ? ' withShrink' : ''} ${className}`}>
<StyledDiv className={`ui--AddressMini${isHighlight ? ' isHighlight' : ''}${isPadded ? ' padded' : ''}${withShrink ? ' withShrink' : ''} ${className}`}>
{label && (
<label className='ui--AddressMini-label'>{label}</label>
)}
@ -100,11 +100,11 @@ function AddressMini ({ balance, bonded, children, className = '', iconInfo, isH
<div className='ui--AddressMini-summary'>{summary}</div>
)}
</div>
</div>
</StyledDiv>
);
}
export default React.memo(styled(AddressMini)`
const StyledDiv = styled.div`
overflow-x: hidden;
padding: 0 0.25rem 0 1rem;
text-align: left;
@ -190,4 +190,6 @@ export default React.memo(styled(AddressMini)`
margin-top: -0.2rem;
text-align: left;
}
`);
`;
export default React.memo(AddressMini);

View File

@ -19,7 +19,7 @@ export interface Props extends RowProps {
label?: string;
noDefaultNameOpacity?: boolean;
overlay?: React.ReactNode;
value: AccountId | AccountIndex | Address | string;
value?: AccountId | AccountIndex | Address | string | null;
withSidebar?: boolean;
withTags?: boolean;
}
@ -35,7 +35,7 @@ function AddressRow ({ buttons, children, className, defaultName, fullLength = f
const address = value && isValid ? value : DEFAULT_ADDR;
return (
<Row
<StyledRow
address={address}
buttons={buttons}
className={className}
@ -60,7 +60,7 @@ function AddressRow ({ buttons, children, className, defaultName, fullLength = f
>
{children}
{overlay}
</Row>
</StyledRow>
);
}
@ -69,7 +69,7 @@ export {
AddressRow
};
export default React.memo(styled(AddressRow)`
const StyledRow = styled(Row)`
button.u.ui--Icon.editButton {
padding: 0 .3em .3em .3em;
color: #2e86ab;
@ -109,4 +109,6 @@ export default React.memo(styled(AddressRow)`
.ui--AddressRow-placeholder {
opacity: var(--opacity-light);
}
`);
`;
export default React.memo(AddressRow);

View File

@ -25,7 +25,7 @@ interface Props {
function AddressSmall ({ children, className = '', defaultName, onClickName, overrideName, parentAddress, toggle, value, withShortAddress = false, withSidebar = true }: Props): React.ReactElement<Props> {
return (
<div className={`ui--AddressSmall ${className} ${(parentAddress || withShortAddress) ? 'withPadding' : ''}`}>
<StyledDiv className={`ui--AddressSmall ${className} ${(parentAddress || withShortAddress) ? 'withPadding' : ''}`}>
<span className='ui--AddressSmall-icon'>
<IdentityIcon value={value as Uint8Array} />
</span>
@ -55,11 +55,11 @@ function AddressSmall ({ children, className = '', defaultName, onClickName, ove
</div>
)}
</span>
</div>
</StyledDiv>
);
}
export default React.memo(styled(AddressSmall)`
const StyledDiv = styled.div`
overflow-x: hidden;
text-overflow: ellipsis;
white-space: nowrap;
@ -111,4 +111,6 @@ export default React.memo(styled(AddressSmall)`
cursor: help;
}
}
`);
`;
export default React.memo(AddressSmall);

View File

@ -35,7 +35,7 @@ function AddressToggle ({ address, className = '', filter, isHidden, noToggle, o
);
return (
<div
<StyledDiv
className={`ui--AddressToggle ${className}${(value || noToggle) ? ' isAye' : ' isNay'}${isHidden || !isVisible ? ' isHidden' : ''}`}
onClick={_onClick}
>
@ -52,11 +52,11 @@ function AddressToggle ({ address, className = '', filter, isHidden, noToggle, o
/>
</div>
)}
</div>
</StyledDiv>
);
}
export default React.memo(styled(AddressToggle)`
const StyledDiv = styled.div`
align-items: flex-start;
border: 1px solid transparent; /* #eee */
border-radius: 0.25rem;
@ -104,4 +104,6 @@ export default React.memo(styled(AddressToggle)`
opacity: 1;
}
}
`);
`;
export default React.memo(AddressToggle);

View File

@ -16,7 +16,7 @@ interface Props {
function AvatarItem ({ children, className = '', icon, isBig, subtitle, title }: Props): React.ReactElement<Props> {
return (
<div className={['ui--AvatarItem', className, isBig && 'big'].join(' ')}>
<StyledDiv className={['ui--AvatarItem', className, isBig && 'big'].join(' ')}>
<div className='ui--AvatarItem-icon'>
{icon}
</div>
@ -29,11 +29,11 @@ function AvatarItem ({ children, className = '', icon, isBig, subtitle, title }:
</div>
</div>
{children}
</div>
</StyledDiv>
);
}
export default React.memo(styled(AvatarItem)`
const StyledDiv = styled.div`
& {
display: flex;
align-items: center;
@ -77,4 +77,6 @@ export default React.memo(styled(AvatarItem)`
}
}
}
`);
`;
export default React.memo(AvatarItem);

View File

@ -13,7 +13,7 @@ import Tooltip from './Tooltip';
interface Props {
className?: string;
color?: 'blue' | 'gray' | 'green' | 'highlight' | 'normal' | 'orange' | 'purple' | 'red' | 'transparent' | 'white';
color?: 'blue' | 'counter' | 'gray' | 'green' | 'highlight' | 'normal' | 'orange' | 'purple' | 'red' | 'transparent' | 'white';
hover?: React.ReactNode;
hoverAction?: React.ReactNode;
icon?: IconName;
@ -48,7 +48,7 @@ function Badge ({ className = '', color = 'normal', hover, hoverAction, icon, in
), [color, hover, hoverAction, onClick]);
return (
<div
<StyledDiv
{...extraProps}
className={`ui--Badge${hover ? ' isTooltip' : ''}${isBlock ? ' isBlock' : ''}${isSmall ? ' isSmall' : ''}${onClick ? ' isClickable' : ''}${isHighlight ? ' highlight--bg' : ''} ${color}Color ${className}${icon ? ' withIcon' : ''}${info ? ' withInfo' : ''}${hoverAction ? ' withAction' : ''} ${theme}Theme `}
data-testid={badgeTestId}
@ -72,12 +72,12 @@ function Badge ({ className = '', color = 'normal', hover, hoverAction, icon, in
trigger={trigger}
/>
)}
</div>
</StyledDiv>
);
}
// FIXME We really need to get rid of the px sizing here
export default React.memo(styled(Badge)`
const StyledDiv = styled.div`
border-radius: 16px;
box-sizing: border-box;
color: #eeedec;
@ -223,4 +223,6 @@ export default React.memo(styled(Badge)`
.action-icon {
margin-left: 4px;
}
`);
`;
export default React.memo(Badge);

View File

@ -44,7 +44,7 @@ function Button ({ activeOnEnter, children, className = '', dataTestId = '', ico
}, [activeOnEnter, listenKeyboard]);
return (
<button
<StyledButton
className={`ui--Button${label ? ' hasLabel' : ''}${isBasic ? ' isBasic' : ''}${isCircular ? ' isCircular' : ''}${isFull ? ' isFull' : ''}${isIcon ? ' isIcon' : ''}${(isBusy || isDisabled) ? ' isDisabled' : ''}${isBusy ? ' isBusy' : ''}${isReadOnly ? ' isReadOnly' : ''}${isSelected ? ' isSelected' : ''}${isToplevel ? ' isToplevel' : ''}${withoutLink ? ' withoutLink' : ''} ${className}`}
data-testid={dataTestId}
onClick={_onClick}
@ -61,13 +61,13 @@ function Button ({ activeOnEnter, children, className = '', dataTestId = '', ico
variant='cover'
/>
)}
</button>
</StyledButton>
);
}
const ICON_PADDING = 0.5;
export default React.memo(styled(Button)`
const StyledButton = styled.button`
background: transparent;
border: none;
color: inherit;
@ -153,4 +153,6 @@ export default React.memo(styled(Button)`
&.isDisabled {
color: #bcbbba;
}
`);
`;
export default React.memo(Button);

View File

@ -8,14 +8,14 @@ import styled from 'styled-components';
function ButtonGroup ({ children, className = '', isCentered }: GroupProps): React.ReactElement<GroupProps> {
return (
<div className={`ui--Button-Group${isCentered ? ' isCentered' : ''} ${className}`}>
<StyledDiv className={`ui--Button-Group${isCentered ? ' isCentered' : ''} ${className}`}>
{children}
<div className='clear' />
</div>
</StyledDiv>
);
}
export default React.memo(styled(ButtonGroup)`
const StyledDiv = styled.div`
margin: 1rem 0;
text-align: right;
@ -43,4 +43,6 @@ export default React.memo(styled(ButtonGroup)`
.ui--ToggleGroup, .ui--Dropdown {
float: left;
}
`);
`;
export default React.memo(ButtonGroup);

View File

@ -101,7 +101,7 @@ function Call ({ callName, children, className = '', labelHash, labelSignature,
}, [callName, value, withHash, withSignature]);
return (
<div className={`ui--Call ${className}`}>
<StyledDiv className={`ui--Call ${className}`}>
<Params
isDisabled
onError={onError}
@ -146,11 +146,11 @@ function Call ({ callName, children, className = '', labelHash, labelSignature,
)}
</div>
</Params>
</div>
</StyledDiv>
);
}
export default React.memo(styled(Call)`
const StyledDiv = styled.div`
.ui--Labelled.hash .ui--Static {
overflow: hidden;
text-overflow: ellipsis;
@ -180,4 +180,6 @@ export default React.memo(styled(Call)`
> .ui--Params {
margin-top: -0.25rem;
}
`);
`;
export default React.memo(Call);

View File

@ -34,7 +34,7 @@ function CallExpander ({ children, className = '', isHeader, labelHash, labelSig
[value]
);
if (!call) {
if (!call || !value) {
return null;
}

View File

@ -14,13 +14,13 @@ interface Props {
function Card ({ children, className = '', isError, isSuccess, withBottomMargin }: Props): React.ReactElement<Props> {
return (
<article className={`ui--Card ${className}${(isError && !isSuccess) ? ' error' : ''}${(!isError && isSuccess) ? ' success' : ''}${withBottomMargin ? ' withBottomMargin' : ''}`}>
<StyledArticle className={`ui--Card ${className}${(isError && !isSuccess) ? ' error' : ''}${(!isError && isSuccess) ? ' success' : ''}${withBottomMargin ? ' withBottomMargin' : ''}`}>
{children}
</article>
</StyledArticle>
);
}
export default React.memo(styled(Card)`
const StyledArticle = styled.article`
position: relative;
flex: 1 1;
min-width: 24%;
@ -79,4 +79,6 @@ export default React.memo(styled(Card)`
&.withBottomMargin {
margin-bottom: 1.5rem;
}
`);
`;
export default React.memo(Card);

View File

@ -57,7 +57,7 @@ function CardSummary ({ children, className = '', label, progress }: Props): Rea
const testidSuffix = (label ?? '').toString();
return (
<article
<StyledArticle
className={className}
data-testid={`card-summary:${testidSuffix}`}
>
@ -96,11 +96,11 @@ function CardSummary ({ children, className = '', label, progress }: Props): Rea
}
</Labelled>
{progress && !progress.hideGraph && <Progress {...progress} />}
</article>
</StyledArticle>
);
}
export default React.memo(styled(CardSummary)`
const StyledArticle = styled.article`
align-items: center;
background: transparent !important;
border: none !important;
@ -161,4 +161,6 @@ export default React.memo(styled(CardSummary)`
font-size: 1.4rem;
}
}
`);
`;
export default React.memo(CardSummary);

View File

@ -6,7 +6,15 @@ import type { BaseProps } from './types';
import React from 'react';
import styled from 'styled-components';
const Wrapper = styled.div`
function BaseChart ({ children, className = '' }: BaseProps): React.ReactElement<BaseProps> {
return (
<StyledDiv className={`ui--Chart ${className}`}>
{children}
</StyledDiv>
);
}
const StyledDiv = styled.div`
position: relative;
display: inline-block;
padding: 1em 1em 0;
@ -14,12 +22,4 @@ const Wrapper = styled.div`
width: 15vw;
`;
function BaseChart ({ children, className = '' }: BaseProps): React.ReactElement<BaseProps> {
return (
<Wrapper className={`ui--Chart ${className}`}>
{children}
</Wrapper>
);
}
export default React.memo(BaseChart);

View File

@ -17,7 +17,7 @@ interface Props {
function KeyPair ({ address, className = '' }: Props): React.ReactElement<Props> {
return (
<div className={`ui--KeyPair ${className}`}>
<StyledDiv className={`ui--KeyPair ${className}`}>
<IdentityIcon
className='icon'
value={address}
@ -28,11 +28,11 @@ function KeyPair ({ address, className = '' }: Props): React.ReactElement<Props>
<div className='address'>
{address}
</div>
</div>
</StyledDiv>
);
}
export default React.memo(styled(KeyPair)`
const StyledDiv = styled.div`
display: flex;
flex-wrap: nowrap;
justify-content: space-between;
@ -69,4 +69,6 @@ export default React.memo(styled(KeyPair)`
text-transform: uppercase;
}
}
`);
`;
export default React.memo(KeyPair);

View File

@ -187,7 +187,7 @@ class InputAddress extends React.PureComponent<Props, State> {
: actualValue;
return (
<Dropdown
<StyledDropdown
className={`ui--InputAddress${hideAddress ? ' hideAddress' : ''} ${className}`}
defaultValue={_defaultValue}
isDisabled={isDisabled}
@ -322,8 +322,7 @@ class InputAddress extends React.PureComponent<Props, State> {
};
}
const ExportedComponent = withMulti(
styled(InputAddress)`
const StyledDropdown = styled(Dropdown)`
.ui.dropdown .text {
width: 100%;
}
@ -364,7 +363,10 @@ const ExportedComponent = withMulti(
flex: 0;
max-width: 0;
}
`,
`;
const ExportedComponent = withMulti(
InputAddress,
withObservable(keyring.keyringOption.optionsSubject, {
propName: 'optionsAll',
transform: (optionsAll: KeyringOptions): Record<string, (Option | React.ReactNode)[]> =>

View File

@ -13,8 +13,8 @@ interface Props {
}
function Selected ({ address, filter, isHidden, onDeselect }: Props): React.ReactElement<Props> | null {
const _onDeselect = useCallback(
(): void => onDeselect(address),
const onChange = useCallback(
() => onDeselect(address),
[address, onDeselect]
);
@ -27,7 +27,7 @@ function Selected ({ address, filter, isHidden, onDeselect }: Props): React.Reac
address={address}
filter={filter}
noToggle
onChange={_onDeselect}
onChange={onChange}
/>
);
}

View File

@ -1,51 +0,0 @@
// Copyright 2017-2023 @polkadot/react-components authors & contributors
// SPDX-License-Identifier: Apache-2.0
import React from 'react';
import { Draggable, DraggableProvided, DraggableStateSnapshot } from 'react-beautiful-dnd';
import { createRoot } from 'react-dom/client';
import { PORTAL_ID } from '../../../apps/src/Apps';
import AddressToggle from '../AddressToggle';
interface Props {
address: string;
index: number;
onDeselect: (index: number) => void;
}
const portal = document.getElementById(PORTAL_ID) as HTMLElement;
function Selected ({ address, index, onDeselect }: Props): React.ReactElement<Props> {
return (
<Draggable
draggableId={address}
index={index}
key={address}
>
{(provided: DraggableProvided, snapshot: DraggableStateSnapshot): React.ReactElement => {
const element = (
<div
// eslint-disable-next-line @typescript-eslint/unbound-method
ref={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps}
>
<AddressToggle
address={address}
className={snapshot.isDragging ? 'isDragging' : ''}
noToggle
onChange={onDeselect}
/>
</div>
);
return snapshot.isDragging
? createRoot(portal).render(element) as unknown as React.ReactElement
: element;
}}
</Draggable>
);
}
export default React.memo(Selected);

View File

@ -49,18 +49,18 @@ function InputAddressMulti ({ available, availableLabel, className = '', default
selected && onChange(selected);
}, [onChange, selected]);
const _onSelect = useCallback(
const onSelect = useCallback(
(address: string) => setSelected((prev) => include(prev, address, maxCount)),
[maxCount]
);
const _onDeselect = useCallback(
const onDeselect = useCallback(
(address: string) => setSelected((prev) => exclude(prev, address)),
[]
);
return (
<div className={`ui--InputAddressMulti ${className}`}>
<StyledDiv className={`ui--InputAddressMulti ${className}`}>
<Input
autoFocus
className='ui--InputAddressMulti-Input'
@ -78,7 +78,7 @@ function InputAddressMulti ({ available, availableLabel, className = '', default
<Selected
address={address}
key={address}
onDeselect={_onDeselect}
onDeselect={onDeselect}
/>
))}
</div>
@ -94,18 +94,18 @@ function InputAddressMulti ({ available, availableLabel, className = '', default
filter={filter}
isHidden={selected?.includes(address)}
key={address}
onSelect={_onSelect}
onSelect={onSelect}
/>
))
}
</div>
</div>
</div>
</div>
</StyledDiv>
);
}
export default React.memo(styled(InputAddressMulti)`
const StyledDiv = styled.div`
border-top-width: 0px;
margin-left: 2rem;
width: calc(100% - 2rem);
@ -159,4 +159,6 @@ export default React.memo(styled(InputAddressMulti)`
}
}
}
`);
`;
export default React.memo(InputAddressMulti);

View File

@ -5,7 +5,7 @@ import type { PopupWindowProps as Props } from './types';
import React from 'react';
import { createPortal } from 'react-dom';
import styled, { css } from 'styled-components';
import styled from 'styled-components';
import { usePopupWindow } from '@polkadot/react-hooks/usePopupWindow';
@ -13,8 +13,8 @@ function PopupWindow ({ children, className = '', position, triggerRef, windowRe
const { pointerStyle, renderCoords: { x, y } } = usePopupWindow(windowRef, triggerRef, position);
return createPortal(
<div
className={`${className} ${pointerStyle}Pointer`}
<StyledDiv
className={`${className} ${pointerStyle}Pointer ${position}Position`}
data-testid='popup-window'
ref={windowRef}
style={
@ -25,12 +25,12 @@ function PopupWindow ({ children, className = '', position, triggerRef, windowRe
}
>
{children}
</div>,
</StyledDiv>,
document.body
);
}
export default React.memo(styled(PopupWindow)`
const StyledDiv = styled.div`
background-color: var(--bg-menu);
border: 1px solid #d4d4d5;
border-radius: 4px;
@ -43,28 +43,30 @@ export default React.memo(styled(PopupWindow)`
top: 0;
z-index: -1;
&.leftPosition {
&::before {
left: unset;
right: 0.75rem;
}
}
&.rightPosition {
&::before {
left: 0.75rem;
right: unset;
}
}
&::before {
background-color: var(--bg-menu);
bottom: -0.5rem;
box-shadow: 1px 1px 0 0 #bababc;
content: '';
height: 1rem;
position: absolute;
right: 50%;
top: unset;
${({ position }) => position === 'left' && css`
left: unset;
right: 0.75rem;
`}
${({ position }) => position === 'right' && css`
left: 0.75rem;
right: unset;
`}
content: '';
background-color: var(--bg-menu);
width: 1rem;
height: 1rem;
transform: rotate(45deg);
z-index: 2;
}
@ -97,4 +99,6 @@ export default React.memo(styled(PopupWindow)`
& > *:last-child:not(.ui--Menu) {
margin-bottom: 1rem;
}
`);
`;
export default React.memo(PopupWindow);

View File

@ -44,7 +44,7 @@ function Popup ({ children, className = '', closeOnScroll, isDisabled, onCloseAc
}, [isOpen, onCloseAction]);
return (
<div className={`ui--Popup ${themeClassName} ${className}`}>
<StyledDiv className={`ui--Popup ${themeClassName} ${className}`}>
{isOpen && (
<PopupWindow
position={position}
@ -68,13 +68,15 @@ function Popup ({ children, className = '', closeOnScroll, isDisabled, onCloseAc
/>
)}
</div>
</div>
</StyledDiv>
);
}
export default React.memo(styled(Popup)`
const StyledDiv = styled.div`
display: inline-flex;
flex-direction: column;
justify-content: center;
position: relative;
`);
`;
export default React.memo(Popup);

View File

@ -157,7 +157,7 @@ export interface RowProps {
buttons?: React.ReactNode;
children?: React.ReactNode;
className?: string;
defaultName?: string;
defaultName?: string | null;
details?: React.ReactNode;
icon?: React.ReactNode;
iconInfo?: React.ReactNode;

View File

@ -171,15 +171,14 @@ function Status ({ className = '' }: Props): React.ReactElement<Props> | null {
}
return (
<div className={`ui--Status ${className}`}>
<StyledDiv className={`ui--Status ${className}`}>
{allTx.map(renderItem)}
{allSt.map(renderStatus)}
</div>
</StyledDiv>
);
}
export default React.memo(styled(Status)`
/* bottom: 0; */
const StyledDiv = styled.div`
display: inline-block;
overflow: hidden;
position: fixed;
@ -308,4 +307,6 @@ export default React.memo(styled(Status)`
}
}
}
`);
`;
export default React.memo(Status);

View File

@ -10,7 +10,7 @@ import Icon from '../../Icon';
function Expand ({ className = '', isExpanded, toggle }: Props): React.ReactElement<Props> {
return (
<td
<StyledTd
className={`ui--Table-Column-Expand ${className}`}
onClick={toggle}
>
@ -23,11 +23,11 @@ function Expand ({ className = '', isExpanded, toggle }: Props): React.ReactElem
}
/>
</div>
</td>
</StyledTd>
);
}
export default React.memo(styled(Expand)`
const StyledTd = styled.td`
&& {
box-sizing: content-box;
cursor: pointer;
@ -47,4 +47,6 @@ export default React.memo(styled(Expand)`
width: 1.7rem;
}
}
`);
`;
export default React.memo(Expand);

View File

@ -15,7 +15,7 @@ function Favorite ({ address, className = '', isFavorite, toggle }: Props): Reac
);
return (
<td
<StyledTd
className={`ui--Table-Column-Favorite ${className}`}
onClick={onClick}
>
@ -27,11 +27,11 @@ function Favorite ({ address, className = '', isFavorite, toggle }: Props): Reac
}
icon='star'
/>
</td>
</StyledTd>
);
}
export default React.memo(styled(Favorite)`
const StyledTd = styled.td`
&& {
box-sizing: content-box;
cursor: pointer;
@ -40,4 +40,6 @@ export default React.memo(styled(Favorite)`
text-align: right;
width: 1rem;
}
`);
`;
export default React.memo(Favorite);

View File

@ -10,9 +10,9 @@ import { formatNumber } from '@polkadot/util';
function Id ({ className = '', value }: Props): React.ReactElement<Props> {
return (
<td className={`ui--Table-Column-Id ${className}`}>
<StyledTd className={`ui--Table-Column-Id ${className}`}>
<h2 className='--digits'>{formatNumber(value)}</h2>
</td>
</StyledTd>
);
}
@ -20,11 +20,13 @@ function Id ({ className = '', value }: Props): React.ReactElement<Props> {
// we wrap the display in an h2 with max size text at ~1.3rem, so multiply it out
const WIDTH = `${(5.5 * 1.3).toFixed(3)}ch`;
export default React.memo(styled(Id)`
const StyledTd = styled.td`
&& {
box-sizing: content-box;
min-width: ${WIDTH};
text-align: right;
white-space: nowrap;
width: ${WIDTH};
`);
`;
export default React.memo(Id);

View File

@ -16,13 +16,13 @@ function Foot ({ className = '', footer, isEmpty }: Props): React.ReactElement<P
}
return (
<tfoot className={className}>
<StyledTfoot className={className}>
{footer}
</tfoot>
</StyledTfoot>
);
}
export default React.memo(styled(Foot)`
const StyledTfoot = styled.tfoot`
td {
color: var(--color-table-foot);
font: var(--font-sans);
@ -36,4 +36,6 @@ export default React.memo(styled(Foot)`
tr {
background: var(--bg-page);
}
`);
`;
export default React.memo(Foot);

View File

@ -10,7 +10,7 @@ interface Props {
children?: React.ReactNode;
className?: string;
filter?: React.ReactNode;
header?: (null | undefined | HeaderDef)[];
header?: (false | null | undefined | HeaderDef)[];
isEmpty: boolean;
}
@ -20,7 +20,7 @@ function Head ({ children, className = '', filter, header, isEmpty }: Props): Re
}
return (
<thead className={className}>
<StyledThead className={className}>
{filter && (
<tr className='filter'>
<th colSpan={100}>{filter}</th>
@ -42,11 +42,11 @@ function Head ({ children, className = '', filter, header, isEmpty }: Props): Re
)}
</tr>
{children}
</thead>
</StyledThead>
);
}
export default React.memo(styled(Head)`
const StyledThead = styled.thead`
z-index: 1;
th {
@ -141,4 +141,6 @@ export default React.memo(styled(Head)`
}
}
}
`);
`;
export default React.memo(Head);

View File

@ -51,7 +51,7 @@ function Table ({ children, className = '', empty, emptySpinner, filter, footer,
const tableClassName = `${(isFixed && !isEmpty) ? 'isFixed' : 'isNotFixed'} ${isInline ? 'isInline' : ''} ${splitBody ? 'noMargin' : ''}`;
return (
<div className={`ui--Table ${className} ${splitBody ? 'isSplit' : ''}`}>
<StyledDiv className={`ui--Table ${className} ${splitBody ? 'isSplit' : ''}`}>
{legend}
{splitBody
? (
@ -94,14 +94,14 @@ function Table ({ children, className = '', empty, emptySpinner, filter, footer,
</table>
)
}
</div>
</StyledDiv>
);
}
const BORDER_RADIUS = '0.5rem';
const BORDER_SOLID = '1px solid var(--bg-page)'; // var(--border-table)
export default React.memo(styled(Table)`
const StyledDiv = styled.div`
max-width: 100%;
width: 100%;
@ -523,4 +523,6 @@ export default React.memo(styled(Table)`
}
}
}
`);
`;
export default React.memo(Table);

View File

@ -15,14 +15,14 @@ interface Props {
function CurrentSection ({ className = '', icon, text }: Props): React.ReactElement<Props> {
return (
<div className={`${className} active-tab`}>
<StyledDiv className={`${className} active-tab`}>
<Icon icon={icon} />
<span>{text}</span>
</div>
</StyledDiv>
);
}
export default React.memo(styled(CurrentSection)`
const StyledDiv = styled.div`
margin: 0 2.5rem 0 1.5rem;
font-weight: var(--font-weight-normal);
font-size: var(--font-size-base);
@ -42,4 +42,6 @@ export default React.memo(styled(CurrentSection)`
@media only screen and (max-width: 900px) {
margin: 0 1.5rem;
}
`);
`;
export default React.memo(CurrentSection);

View File

@ -26,7 +26,7 @@ function Tab ({ basePath, className = '', count, hasParams, index, isExact, isRo
const tabIsExact = isExact || !hasParams || index === 0;
return (
<NavLink
<StyledNavLink
activeClassName='tabLinkActive'
className={`ui--Tab ${className}`}
exact={tabIsExact}
@ -43,11 +43,11 @@ function Tab ({ basePath, className = '', count, hasParams, index, isExact, isRo
info={count}
/>
)}
</NavLink>
</StyledNavLink>
);
}
export default React.memo(styled(Tab)`
const StyledNavLink = styled(NavLink)`
align-items: center;
display: flex;
color: #8B8B8B;
@ -97,4 +97,6 @@ export default React.memo(styled(Tab)`
.tabIcon {
margin-left: 0.75rem;
}
`);
`;
export default React.memo(Tab);

View File

@ -10,7 +10,7 @@ interface TabsSectionDelimiterProps {
function TabsSectionDelimiter ({ className = '' }: TabsSectionDelimiterProps): React.ReactElement {
return (
<div className={className}>
<StyledDiv className={className}>
<svg
fill='none'
height='47'
@ -24,11 +24,13 @@ function TabsSectionDelimiter ({ className = '' }: TabsSectionDelimiterProps): R
stroke='#D1D1D1'
/>
</svg>
</div>
</StyledDiv>
);
}
export default React.memo(styled(TabsSectionDelimiter)`
const StyledDiv = styled.div`
height: 100%;
width: auto;
`);
`;
export default React.memo(TabsSectionDelimiter);

View File

@ -4,7 +4,7 @@
import type { Location } from 'history';
import type { SectionType, TabItem } from './types';
import React, { useEffect } from 'react';
import React, { useEffect, useMemo } from 'react';
import { useLocation } from 'react-router-dom';
import styled from 'styled-components';
@ -18,21 +18,21 @@ interface Props {
className?: string;
basePath: string;
hidden?: string[] | null | false;
items: TabItem[];
items: (TabItem | false | null | undefined)[];
}
// redirect on invalid tabs
function redirect (basePath: string, location: Location, items: TabItem[], hidden?: string[] | null | false): void {
function redirect (basePath: string, location: Location, items: (TabItem | false | null | undefined)[], hidden?: string[] | null | false): void {
if (location.pathname !== basePath) {
// Has the form /staking/query/<something>
const [,, section] = location.pathname.split('/');
const alias = items.find(({ alias }) => alias === section);
const alias = items.find((v) => v && v.alias === section);
if (alias) {
window.location.hash = alias.isRoot
? basePath
: `${basePath}/${alias.name}`;
} else if (hidden && (hidden.includes(section) || !items.some(({ isRoot, name }) => !isRoot && name === section))) {
} else if (hidden && (hidden.includes(section) || !items.some((v) => v && !v.isRoot && v.name === section))) {
window.location.hash = basePath;
}
}
@ -42,17 +42,18 @@ function Tabs ({ basePath, className = '', hidden, items }: Props): React.ReactE
const location = useLocation();
const { icon, text } = React.useContext(TabsCtx);
const filtered = useMemo(
() => items.filter((v): v is TabItem => !!v && (!hidden || !hidden.includes(v.name))),
[hidden, items]
);
useEffect(
() => redirect(basePath, location, items, hidden),
[basePath, hidden, items, location]
);
const filtered = hidden
? items.filter(({ name }) => !hidden.includes(name))
: items;
return (
<header className={`ui--Tabs ${className}`}>
<StyledHeader className={`ui--Tabs ${className}`}>
<div className='tabs-container'>
{text && icon && (
<CurrentSection
@ -77,11 +78,11 @@ function Tabs ({ basePath, className = '', hidden, items }: Props): React.ReactE
))}
</ul>
</div>
</header>
</StyledHeader>
);
}
export default React.memo(styled(Tabs)`
const StyledHeader = styled.header`
background: var(--bg-tabs);
border-bottom: 1px solid var(--border-tabs);
text-align: left;
@ -114,4 +115,6 @@ export default React.memo(styled(Tabs)`
margin: 0 2.72rem 0 2.35rem;
}
}
`);
`;
export default React.memo(Tabs);

View File

@ -26,18 +26,18 @@ function BlockToTime ({ api, children, className = '', isInline, label, value }:
}
return (
<div className={`.ui--BlockToTime ${className}${isInline ? ' isInline' : ''}`}>
<StyledDiv className={`ui--BlockToTime ${className} ${isInline ? 'isInline' : ''}`}>
{label || ''}{text.split(' ').map((v, index) =>
<span
className={index % 2 ? 'timeUnits' : undefined}
key={index}
>{v}</span>
)}{children}
</div>
</StyledDiv>
);
}
export default React.memo(styled(BlockToTime)`
const StyledDiv = styled.div`
&.isInline {
display: inline-block;
}
@ -49,4 +49,6 @@ export default React.memo(styled(BlockToTime)`
span.timeUnits {
font-size: var(--font-percent-tiny);
}
`);
`;
export default React.memo(BlockToTime);

View File

@ -76,16 +76,16 @@ function Elapsed ({ children, className = '', value }: Props): React.ReactElemen
}, []);
return (
<div className={`ui--Elapsed ${className} --digits`}>
<StyledDiv className={`ui--Elapsed ${className} --digits`}>
{getDisplayValue(now, value)}{children}
</div>
</StyledDiv>
);
}
export default React.memo(styled(Elapsed)`
white-space: nowrap;
const StyledDiv = styled.div`
.timeUnit {
font-size: var(--font-percent-tiny);
}
`);
`;
export default React.memo(Elapsed);

View File

@ -16,12 +16,12 @@ import { useTranslation } from './translate';
interface Props {
children?: React.ReactNode;
className?: string;
format?: [number, string];
format?: [decimals: number, unit: string];
formatIndex?: number;
isShort?: boolean;
label?: React.ReactNode;
labelPost?: LabelPost;
value?: Compact<any> | BN | string | null | 'all';
value?: Compact<any> | BN | string | number | null | 'all';
valueFormatted?: string;
withCurrency?: boolean;
withSi?: boolean;
@ -58,7 +58,7 @@ function splitFormat (value: string, label?: LabelPost, isShort?: boolean): Reac
return createElement(prefix, postfix, unit, label, isShort);
}
function applyFormat (value: Compact<any> | BN | string, [decimals, token]: [number, string], withCurrency = true, withSi?: boolean, _isShort?: boolean, labelPost?: LabelPost): React.ReactNode {
function applyFormat (value: Compact<any> | BN | string | number, [decimals, token]: [number, string], withCurrency = true, withSi?: boolean, _isShort?: boolean, labelPost?: LabelPost): React.ReactNode {
const [prefix, postfix] = formatBalance(value, { decimals, forceUnit: '-', withSi: false }).split('.');
const isShort = _isShort || (withSi && prefix.length >= K_LENGTH);
const unitPost = withCurrency ? token : '';
@ -85,7 +85,7 @@ function FormatBalance ({ children, className = '', format, formatIndex, isShort
// labelPost here looks messy, however we ensure we have one less text node
return (
<div className={`ui--FormatBalance ${className}`}>
<StyledSpan className={`ui--FormatBalance ${className}`}>
{label ? <>{label}&nbsp;</> : ''}
<span
className='ui--FormatBalance-value --digits'
@ -101,12 +101,11 @@ function FormatBalance ({ children, className = '', format, formatIndex, isShort
? `-${labelPost.toString()}`
: labelPost
}</span>{children}
</div>
</StyledSpan>
);
}
export default React.memo(styled(FormatBalance)`
display: inline-block;
const StyledSpan = styled.span`
vertical-align: baseline;
white-space: nowrap;
@ -147,4 +146,6 @@ export default React.memo(styled(FormatBalance)`
.ui--Icon+.ui--FormatBalance-value {
margin-left: 0.375rem;
}
`);
`;
export default React.memo(FormatBalance);