feat(ui-toolkit): increase checkbox and radio clickable area (#4906)

This commit is contained in:
Bartłomiej Głownia 2023-10-04 12:50:02 +02:00 committed by GitHub
parent 6e7b87d9ef
commit 797db6ee93
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 131 additions and 119 deletions

View File

@ -40,7 +40,7 @@ context.skip('Node switcher', { tags: '@regression' }, function () {
const errorTypeTxt = 'Error: invalid url'; const errorTypeTxt = 'Error: invalid url';
const nodeErrorTxt = 'fakeUrl is not a valid url.'; const nodeErrorTxt = 'fakeUrl is not a valid url.';
cy.getByTestId('node-url-custom').click(); cy.getByTestId('node-url-custom').click({ force: true });
cy.getByTestId(customNodeBtn).within(() => { cy.getByTestId(customNodeBtn).within(() => {
cy.get('input').clear().type('fakeUrl'); cy.get('input').clear().type('fakeUrl');

View File

@ -310,7 +310,9 @@ context(
closeStakingDialog(); closeStakingDialog();
navigateTo(navigation.validators); navigateTo(navigation.validators);
clickOnValidatorFromList(0); clickOnValidatorFromList(0);
cy.getByTestId(stakeRemoveStakeRadioButton, txTimeout).click(); cy.getByTestId(stakeRemoveStakeRadioButton, txTimeout).click({
force: true,
});
cy.getByTestId(stakeTokenAmountInputBox).type('-0.1'); cy.getByTestId(stakeTokenAmountInputBox).type('-0.1');
cy.contains('Waiting for next epoch to start', epochTimeout); cy.contains('Waiting for next epoch to start', epochTimeout);
cy.getByTestId(stakeTokenSubmitButton) cy.getByTestId(stakeTokenSubmitButton)
@ -331,7 +333,7 @@ context(
closeStakingDialog(); closeStakingDialog();
navigateTo(navigation.validators); navigateTo(navigation.validators);
clickOnValidatorFromList(0); clickOnValidatorFromList(0);
cy.getByTestId(stakeRemoveStakeRadioButton).click(); cy.getByTestId(stakeRemoveStakeRadioButton).click({ force: true });
cy.getByTestId(stakeTokenAmountInputBox).type('4'); cy.getByTestId(stakeTokenAmountInputBox).type('4');
cy.contains('Waiting for next epoch to start', epochTimeout); cy.contains('Waiting for next epoch to start', epochTimeout);
cy.getByTestId(stakeTokenSubmitButton) cy.getByTestId(stakeTokenSubmitButton)

View File

@ -156,7 +156,7 @@ context('Home Page - verify elements on page', { tags: '@smoke' }, function () {
cy.getByTestId('subscription-cell').should('have.text', 'Yes'); cy.getByTestId('subscription-cell').should('have.text', 'Yes');
}); });
cy.getByTestId('connect').should('be.disabled'); cy.getByTestId('connect').should('be.disabled');
cy.getByTestId('node-url-custom').click(); cy.getByTestId('node-url-custom').click({ force: true });
cy.get('input').should('exist'); cy.get('input').should('exist');
cy.getByTestId('connect').should('be.disabled'); cy.getByTestId('connect').should('be.disabled');
cy.getByTestId('icon-cross').click(); cy.getByTestId('icon-cross').click();

View File

@ -46,7 +46,7 @@ export function stakingValidatorPageAddStake(stake: string) {
export function stakingValidatorPageRemoveStake(stake: string) { export function stakingValidatorPageRemoveStake(stake: string) {
cy.highlight(`Removing a stake of ${stake}`); cy.highlight(`Removing a stake of ${stake}`);
cy.get(removeStakeRadioButton, epochTimeout).click(); cy.get(removeStakeRadioButton, epochTimeout).click({ force: true });
cy.get(tokenAmountInputBox).type(stake); cy.get(tokenAmountInputBox).type(stake);
waitForBeginningOfEpoch(); waitForBeginningOfEpoch();
cy.get(tokenSubmitButton) cy.get(tokenSubmitButton)
@ -70,9 +70,13 @@ export function stakingPageAssociateTokens(
cy.highlight(`Associating ${amount} tokens from ${type}`); cy.highlight(`Associating ${amount} tokens from ${type}`);
cy.get(ethWalletAssociateButton).first().click(); cy.get(ethWalletAssociateButton).first().click();
if (type === 'wallet') { if (type === 'wallet') {
cy.get(associateWalletRadioButton, { timeout: 30000 }).click(); cy.get(associateWalletRadioButton, { timeout: 30000 }).click({
force: true,
});
} else if (type === 'contract') { } else if (type === 'contract') {
cy.get(associateContractRadioButton, { timeout: 30000 }).click(); cy.get(associateContractRadioButton, { timeout: 30000 }).click({
force: true,
});
} else { } else {
cy.highlight(`${type} is not association option`); cy.highlight(`${type} is not association option`);
} }

View File

@ -61,7 +61,7 @@ describe('home', { tags: '@regression' }, () => {
// 0006-NETW-020 // 0006-NETW-020
cy.getByTestId(nodeHealthTrigger).click(); cy.getByTestId(nodeHealthTrigger).click();
cy.getByTestId('connect').should('be.disabled'); cy.getByTestId('connect').should('be.disabled');
cy.getByTestId('node-url-custom').click(); cy.getByTestId('node-url-custom').click({ force: true });
cy.getByTestId('connect').should('be.disabled'); cy.getByTestId('connect').should('be.disabled');
cy.get("input[placeholder='https://']") cy.get("input[placeholder='https://']")
.focus() .focus()

View File

@ -258,21 +258,21 @@ export const TransferForm = ({
)} )}
</TradingFormGroup> </TradingFormGroup>
<div className="mb-4"> <div className="mb-4">
<TradingCheckbox <Tooltip
name="include-transfer-fee" description={t(
disabled={!transferAmount} `The fee will be taken from the amount you are transferring.`
label={ )}
<Tooltip >
description={t( <div>
`The fee will be taken from the amount you are transferring.` <TradingCheckbox
)} name="include-transfer-fee"
> disabled={!transferAmount}
<div>{t('Include transfer fee')}</div> label={t('Include transfer fee')}
</Tooltip> checked={includeFee}
} onCheckedChange={() => setIncludeFee(!includeFee)}
checked={includeFee} />
onCheckedChange={() => setIncludeFee(!includeFee)} </div>
/> </Tooltip>
</div> </div>
{transferAmount && fee && ( {transferAmount && fee && (
<TransferFee <TransferFee

View File

@ -494,16 +494,16 @@ const TimeInForce = ({
); );
const ReduceOnly = () => ( const ReduceOnly = () => (
<Checkbox <Tooltip description={<span>{t(REDUCE_ONLY_TOOLTIP)}</span>}>
name="reduce-only" <div>
checked={true} <Checkbox
disabled={true} name="reduce-only"
label={ checked={true}
<Tooltip description={<span>{t(REDUCE_ONLY_TOOLTIP)}</span>}> disabled={true}
<>{t('Reduce only')}</> label={t('Reduce only')}
</Tooltip> />
} </div>
/> </Tooltip>
); );
const NotionalAndFees = ({ const NotionalAndFees = ({

View File

@ -548,62 +548,62 @@ export const DealTicket = ({
name="postOnly" name="postOnly"
control={control} control={control}
render={({ field }) => ( render={({ field }) => (
<Checkbox <Tooltip
name="post-only" description={
checked={!disablePostOnlyCheckbox && field.value} <span>
disabled={disablePostOnlyCheckbox} {disablePostOnlyCheckbox
onCheckedChange={(postOnly) => { ? t(
field.onChange(postOnly); '"Post only" can not be used on "Fill or Kill" or "Immediate or Cancel" orders.'
setValue('reduceOnly', false); )
}} : t(
label={ '"Post only" will ensure the order is not filled immediately but is placed on the order book as a passive order. When the order is processed it is either stopped (if it would not be filled immediately), or placed in the order book as a passive order until the price taker matches with it.'
<Tooltip )}
description={ </span>
<span>
{disablePostOnlyCheckbox
? t(
'"Post only" can not be used on "Fill or Kill" or "Immediate or Cancel" orders.'
)
: t(
'"Post only" will ensure the order is not filled immediately but is placed on the order book as a passive order. When the order is processed it is either stopped (if it would not be filled immediately), or placed in the order book as a passive order until the price taker matches with it.'
)}
</span>
}
>
<span className="text-xs">{t('Post only')}</span>
</Tooltip>
} }
/> >
<div>
<Checkbox
name="post-only"
checked={!disablePostOnlyCheckbox && field.value}
disabled={disablePostOnlyCheckbox}
onCheckedChange={(postOnly) => {
field.onChange(postOnly);
setValue('reduceOnly', false);
}}
label={t('Post only')}
/>
</div>
</Tooltip>
)} )}
/> />
<Controller <Controller
name="reduceOnly" name="reduceOnly"
control={control} control={control}
render={({ field }) => ( render={({ field }) => (
<Checkbox <Tooltip
name="reduce-only" description={
checked={!disableReduceOnlyCheckbox && field.value} <span>
disabled={disableReduceOnlyCheckbox} {disableReduceOnlyCheckbox
onCheckedChange={(reduceOnly) => { ? t(
field.onChange(reduceOnly); '"Reduce only" can be used only with non-persistent orders, such as "Fill or Kill" or "Immediate or Cancel".'
setValue('postOnly', false); )
}} : t(REDUCE_ONLY_TOOLTIP)}
label={ </span>
<Tooltip
description={
<span>
{disableReduceOnlyCheckbox
? t(
'"Reduce only" can be used only with non-persistent orders, such as "Fill or Kill" or "Immediate or Cancel".'
)
: t(REDUCE_ONLY_TOOLTIP)}
</span>
}
>
<span className="text-xs">{t('Reduce only')}</span>
</Tooltip>
} }
/> >
<div>
<Checkbox
name="reduce-only"
checked={!disableReduceOnlyCheckbox && field.value}
disabled={disableReduceOnlyCheckbox}
onCheckedChange={(reduceOnly) => {
field.onChange(reduceOnly);
setValue('postOnly', false);
}}
label={t('Reduce only')}
/>
</div>
</Tooltip>
)} )}
/> />
</div> </div>
@ -614,26 +614,26 @@ export const DealTicket = ({
name="iceberg" name="iceberg"
control={control} control={control}
render={({ field }) => ( render={({ field }) => (
<Checkbox <Tooltip
name="iceberg" description={
checked={field.value} <p>
onCheckedChange={field.onChange} {t(`Trade only a fraction of the order size at once.
disabled={disableIcebergCheckbox}
label={
<Tooltip
description={
<p>
{t(`Trade only a fraction of the order size at once.
After the peak size of the order has traded, the size is reset. This is repeated until the order is cancelled, expires, or its full volume trades away. After the peak size of the order has traded, the size is reset. This is repeated until the order is cancelled, expires, or its full volume trades away.
For example, an iceberg order with a size of 1000 and a peak size of 100 will effectively be split into 10 orders with a size of 100 each. For example, an iceberg order with a size of 1000 and a peak size of 100 will effectively be split into 10 orders with a size of 100 each.
Note that the full volume of the order is not hidden and is still reflected in the order book.`)} Note that the full volume of the order is not hidden and is still reflected in the order book.`)}
</p> </p>
}
>
<span className="text-xs">{t('Iceberg')}</span>
</Tooltip>
} }
/> >
<div>
<Checkbox
name="iceberg"
checked={field.value}
onCheckedChange={field.onChange}
disabled={disableIcebergCheckbox}
label={t('Iceberg')}
/>
</div>
</Tooltip>
)} )}
/> />
</div> </div>

View File

@ -4,6 +4,8 @@ import classNames from 'classnames';
import type { ReactNode } from 'react'; import type { ReactNode } from 'react';
type CheckedState = boolean | 'indeterminate'; type CheckedState = boolean | 'indeterminate';
export const labelClasses =
"relative before:content-[''] before:block before:absolute before:top-1/2 before:left-[0] before:right-[0] before:-translate-y-1/2 before:h-6";
export interface CheckboxProps { export interface CheckboxProps {
checked?: CheckedState; checked?: CheckedState;
label?: ReactNode; label?: ReactNode;
@ -30,7 +32,7 @@ export const Checkbox = ({
); );
return ( return (
<div className="flex gap-1"> <label className={`flex gap-1 ${labelClasses}`} htmlFor={name}>
<CheckboxPrimitive.Root <CheckboxPrimitive.Root
name={name} name={name}
id={name} id={name}
@ -55,14 +57,13 @@ export const Checkbox = ({
)} )}
</CheckboxPrimitive.CheckboxIndicator> </CheckboxPrimitive.CheckboxIndicator>
</CheckboxPrimitive.Root> </CheckboxPrimitive.Root>
<label <span
htmlFor={name}
className={classNames('text-sm flex-1', { className={classNames('text-sm flex-1', {
'dark:text-neutral-400 text-neutral-600': disabled, 'dark:text-neutral-400 text-neutral-600': disabled,
})} })}
> >
{label} {label}
</label> </span>
</div> </label>
); );
}; };

View File

@ -2,6 +2,7 @@ import { forwardRef } from 'react';
import * as RadioGroupPrimitive from '@radix-ui/react-radio-group'; import * as RadioGroupPrimitive from '@radix-ui/react-radio-group';
import classNames from 'classnames'; import classNames from 'classnames';
import type { ReactNode } from 'react'; import type { ReactNode } from 'react';
import { labelClasses } from '../checkbox';
export interface RadioGroupProps { export interface RadioGroupProps {
name?: string; name?: string;
@ -56,7 +57,7 @@ interface RadioProps {
} }
export const Radio = ({ id, value, label, disabled }: RadioProps) => { export const Radio = ({ id, value, label, disabled }: RadioProps) => {
const wrapperClasses = classNames('flex items-center gap-2', { const wrapperClasses = classNames('flex items-center gap-2', labelClasses, {
'opacity-40': disabled, 'opacity-40': disabled,
}); });
const itemClasses = classNames( const itemClasses = classNames(
@ -71,7 +72,7 @@ export const Radio = ({ id, value, label, disabled }: RadioProps) => {
'border-black dark:border-white' 'border-black dark:border-white'
); );
return ( return (
<div className={wrapperClasses}> <label className={wrapperClasses} htmlFor={id}>
<RadioGroupPrimitive.Item <RadioGroupPrimitive.Item
value={value} value={value}
className={itemClasses} className={itemClasses}
@ -81,9 +82,7 @@ export const Radio = ({ id, value, label, disabled }: RadioProps) => {
> >
<RadioGroupPrimitive.Indicator className={indicatorClasses} /> <RadioGroupPrimitive.Indicator className={indicatorClasses} />
</RadioGroupPrimitive.Item> </RadioGroupPrimitive.Item>
<label htmlFor={id} className={disabled ? '' : 'cursor-pointer'}> <span className={disabled ? '' : 'cursor-pointer'}>{label}</span>
{label} </label>
</label>
</div>
); );
}; };

View File

@ -2,6 +2,7 @@ import { VegaIcon, VegaIconNames } from '../icon';
import * as CheckboxPrimitive from '@radix-ui/react-checkbox'; import * as CheckboxPrimitive from '@radix-ui/react-checkbox';
import classNames from 'classnames'; import classNames from 'classnames';
import type { ReactNode } from 'react'; import type { ReactNode } from 'react';
import { labelClasses } from '../checkbox';
type CheckedState = boolean | 'indeterminate'; type CheckedState = boolean | 'indeterminate';
export interface TradingCheckboxProps { export interface TradingCheckboxProps {
@ -29,7 +30,10 @@ export const TradingCheckbox = ({
); );
return ( return (
<div className="flex gap-1.5 items-center"> <label
htmlFor={name}
className={`flex gap-1.5 items-center ${labelClasses}`}
>
<CheckboxPrimitive.Root <CheckboxPrimitive.Root
name={name} name={name}
id={name} id={name}
@ -50,14 +54,13 @@ export const TradingCheckbox = ({
)} )}
</CheckboxPrimitive.CheckboxIndicator> </CheckboxPrimitive.CheckboxIndicator>
</CheckboxPrimitive.Root> </CheckboxPrimitive.Root>
<label <span
htmlFor={name}
className={classNames('text-xs flex-1', { className={classNames('text-xs flex-1', {
'text-vega-clight-200 dark:text-vega-cdark-200': disabled, 'text-vega-clight-200 dark:text-vega-cdark-200': disabled,
})} })}
> >
{label} {label}
</label> </span>
</div> </label>
); );
}; };

View File

@ -2,6 +2,7 @@ import { forwardRef } from 'react';
import * as RadioGroupPrimitive from '@radix-ui/react-radio-group'; import * as RadioGroupPrimitive from '@radix-ui/react-radio-group';
import classNames from 'classnames'; import classNames from 'classnames';
import type { ReactNode } from 'react'; import type { ReactNode } from 'react';
import { labelClasses } from '../checkbox';
export interface TradingRadioGroupProps { export interface TradingRadioGroupProps {
name?: string; name?: string;
@ -59,7 +60,10 @@ interface RadioProps {
} }
export const TradingRadio = ({ id, value, label, disabled }: RadioProps) => { export const TradingRadio = ({ id, value, label, disabled }: RadioProps) => {
const wrapperClasses = classNames('flex items-center gap-1.5 text-xs'); const wrapperClasses = classNames(
'flex items-center gap-1.5 text-xs',
labelClasses
);
const itemClasses = classNames( const itemClasses = classNames(
'flex justify-center items-center', 'flex justify-center items-center',
'w-3 h-3 rounded-full border', 'w-3 h-3 rounded-full border',
@ -74,7 +78,7 @@ export const TradingRadio = ({ id, value, label, disabled }: RadioProps) => {
'border-vega-clight-700 dark:border-vega-cdark-700' 'border-vega-clight-700 dark:border-vega-cdark-700'
); );
return ( return (
<div className={wrapperClasses}> <label className={wrapperClasses} htmlFor={id}>
<RadioGroupPrimitive.Item <RadioGroupPrimitive.Item
value={value} value={value}
className={itemClasses} className={itemClasses}
@ -84,8 +88,7 @@ export const TradingRadio = ({ id, value, label, disabled }: RadioProps) => {
> >
<RadioGroupPrimitive.Indicator className={indicatorClasses} /> <RadioGroupPrimitive.Indicator className={indicatorClasses} />
</RadioGroupPrimitive.Item> </RadioGroupPrimitive.Item>
<label <span
htmlFor={id}
className={ className={
disabled disabled
? 'text-vega-clight-200 dark:text-vega-cdark-200' ? 'text-vega-clight-200 dark:text-vega-cdark-200'
@ -93,7 +96,7 @@ export const TradingRadio = ({ id, value, label, disabled }: RadioProps) => {
} }
> >
{label} {label}
</label> </span>
</div> </label>
); );
}; };