diff --git a/apps/explorer/src/app/components/jump-to/index.tsx b/apps/explorer/src/app/components/jump-to/index.tsx
index c1807a9e3..c00f47de8 100644
--- a/apps/explorer/src/app/components/jump-to/index.tsx
+++ b/apps/explorer/src/app/components/jump-to/index.tsx
@@ -36,7 +36,12 @@ export const JumpTo = ({
placeholder={placeholder}
className="max-w-[200px]"
/>
-
-
-
+
+
{t('staking')}
-
+
diff --git a/apps/token/src/config/env.ts b/apps/token/src/config/env.ts
index 48df11587..1e5d972c8 100644
--- a/apps/token/src/config/env.ts
+++ b/apps/token/src/config/env.ts
@@ -55,6 +55,9 @@ export const ENV = {
commit: windowOrDefault('NX_COMMIT_REF'),
branch: windowOrDefault('NX_BRANCH'),
vegaUrl: windowOrDefault('NX_VEGA_URL'),
+ urlConnect: TRUTHY.includes(windowOrDefault('NX_ETH_URL_CONNECT')),
+ ethWalletMnemonic: windowOrDefault('NX_ETH_WALLET_MNEMONIC'),
+ localProviderUrl: windowOrDefault('NX_LOCAL_PROVIDER_URL'),
flags: {
NETWORK_DOWN: TRUTHY.includes(windowOrDefault('NX_NETWORK_DOWN')),
HOSTED_WALLET_ENABLED: TRUTHY.includes(
diff --git a/apps/token/src/hooks/__mocks__/use-tranches.ts b/apps/token/src/hooks/__mocks__/use-tranches.ts
index 42afaf090..2aa866267 100644
--- a/apps/token/src/hooks/__mocks__/use-tranches.ts
+++ b/apps/token/src/hooks/__mocks__/use-tranches.ts
@@ -1,10 +1,8 @@
import React from 'react';
-import { useContracts } from '../../contexts/contracts/contracts-context';
import mock from './tranches-mock';
import type { Tranche } from '@vegaprotocol/smart-contracts';
export function useTranches() {
- const { vesting } = useContracts();
const [tranches, setTranches] = React.useState(null);
const [error, setError] = React.useState(null);
@@ -17,7 +15,7 @@ export function useTranches() {
}
};
run();
- }, [vesting]);
+ }, []);
return { tranches, error };
}
diff --git a/apps/token/src/hooks/use-refresh-associated-balances.ts b/apps/token/src/hooks/use-refresh-associated-balances.ts
index 6f0831f89..f87ae011e 100644
--- a/apps/token/src/hooks/use-refresh-associated-balances.ts
+++ b/apps/token/src/hooks/use-refresh-associated-balances.ts
@@ -1,3 +1,4 @@
+import { toBigNum } from '@vegaprotocol/react-helpers';
import React from 'react';
import {
@@ -7,23 +8,26 @@ import {
import { useContracts } from '../contexts/contracts/contracts-context';
export function useRefreshAssociatedBalances() {
- const { appDispatch } = useAppState();
+ const {
+ appDispatch,
+ appState: { decimals },
+ } = useAppState();
const { staking, vesting } = useContracts();
return React.useCallback(
async (ethAddress: string, vegaKey: string) => {
const [walletAssociatedBalance, vestingAssociatedBalance] =
await Promise.all([
- staking.stakeBalance(ethAddress, `0x${vegaKey}`),
- vesting.stakeBalance(ethAddress, `0x${vegaKey}`),
+ staking.stakeBalance(ethAddress, vegaKey),
+ vesting.stakeBalance(ethAddress, vegaKey),
]);
appDispatch({
type: AppStateActionType.REFRESH_ASSOCIATED_BALANCES,
- walletAssociatedBalance,
- vestingAssociatedBalance,
+ walletAssociatedBalance: toBigNum(walletAssociatedBalance, decimals),
+ vestingAssociatedBalance: toBigNum(vestingAssociatedBalance, decimals),
});
},
- [staking, vesting, appDispatch]
+ [staking, vesting, appDispatch, decimals]
);
}
diff --git a/apps/token/src/i18n/translations/dev.json b/apps/token/src/i18n/translations/dev.json
index bc61ef421..6f6463837 100644
--- a/apps/token/src/i18n/translations/dev.json
+++ b/apps/token/src/i18n/translations/dev.json
@@ -193,6 +193,7 @@
"noGovernanceTokens": "You need some VEGA tokens to participate in governance",
"youVoted": "You voted",
"changeVote": "Change vote",
+ "voteRequested": "Please confirm transaction in wallet",
"votePending": "Casting vote",
"voteError": "Something went wrong, and your vote was not seen by the network",
"back": "back",
@@ -280,6 +281,7 @@
"stakingHasAssociated": "You have {{tokens}} $VEGA tokens associated.",
"stakingAssociateMoreButton": "Associate more $VEGA tokens with wallet",
"stakingDisassociateButton": "Disassociate $VEGA tokens from wallet",
+ "stakingConfirm": "Open you wallet app to confirm",
"associateButton": "Associate $VEGA tokens with wallet",
"nodeQueryFailed": "Could not get data for validator {{node}}",
"stakeAddPendingTitle": "Adding {{amount}} $VEGA to validator {{node}}",
@@ -540,5 +542,8 @@
"numberOfAgainstVotes": "Number of votes against",
"yesPercentage": "Yes percentage",
"noPercentage": "No percentage",
- "proposalTerms": "Proposal terms"
+ "proposalTerms": "Proposal terms",
+ "currentlySetTo": "Currently set to ",
+ "pass": "Pass",
+ "fail": "Fail"
}
diff --git a/apps/token/src/index.html b/apps/token/src/index.html
index 6396c83af..33627cdd5 100644
--- a/apps/token/src/index.html
+++ b/apps/token/src/index.html
@@ -1,5 +1,5 @@
-
+
diff --git a/apps/token/src/lib/url-connector.ts b/apps/token/src/lib/url-connector.ts
new file mode 100644
index 000000000..0133e0f75
--- /dev/null
+++ b/apps/token/src/lib/url-connector.ts
@@ -0,0 +1,150 @@
+import { ethers, Wallet } from 'ethers';
+import { Connector } from '@web3-react/types';
+
+import { Eip1193Bridge } from '@ethersproject/experimental';
+import type { ConnectionInfo } from '@ethersproject/web';
+import type { Actions } from '@web3-react/types';
+import { ENV } from '../config/env';
+
+export class CustomizedBridge extends Eip1193Bridge {
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ async sendAsync(...args: any) {
+ console.debug('sendAsync called', ...args);
+ return this.send(...args);
+ }
+
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ override async send(...args: any) {
+ console.debug('send called', ...args);
+ const isCallbackForm =
+ typeof args[0] === 'object' && typeof args[1] === 'function';
+ let callback;
+ let method;
+ let params;
+ if (isCallbackForm) {
+ callback = args[1];
+ method = args[0].method;
+ params = args[0].params;
+ } else {
+ method = args[0];
+ params = args[1];
+ }
+ try {
+ // Hacky, https://github.com/ethers-io/ethers.js/issues/1683#issuecomment-1016227588
+
+ // If from is present on eth_call it errors, removing it makes the library set
+ // from as the connected wallet which works fine
+ if (params && params.length && params[0].from && method === 'eth_call')
+ delete params[0].from;
+ let result;
+ // For sending a transaction if we call send it will error
+ // as it wants gasLimit in sendTransaction but hexlify sets the property gas
+ // to gasLimit which makes sensd transaction error.
+ // This has taken the code from the super method for sendTransaction and altered
+ // it slightly to make it work with the gas limit issues.
+ if (
+ params &&
+ params.length &&
+ params[0].from &&
+ method === 'eth_sendTransaction'
+ ) {
+ // Hexlify will not take gas, must be gasLimit, set this property to be gasLimit
+ params[0].gasLimit = params[0].gas;
+ delete params[0].gas;
+ // If from is present on eth_sendTransaction it errors, removing it makes the library set
+ // from as the connected wallet which works fine
+ delete params[0].from;
+ const req = ethers.providers.JsonRpcProvider.hexlifyTransaction(
+ params[0]
+ );
+ // Hexlify sets the gasLimit property to be gas again and send transaction requires gasLimit
+ req['gasLimit'] = req['gas'];
+ delete req['gas'];
+
+ if (!this.signer) {
+ throw new Error('No signer');
+ }
+
+ // Send the transaction
+ const tx = await this.signer.sendTransaction(req);
+ result = tx.hash;
+ } else {
+ // All other transactions the base class works for
+ result = await super.send(method, params);
+ }
+ console.debug('result received', method, params, result);
+ if (isCallbackForm) {
+ callback(null, { result });
+ } else {
+ return result;
+ }
+ } catch (error) {
+ console.error(error);
+ if (isCallbackForm) {
+ callback(error, null);
+ } else {
+ throw error;
+ }
+ }
+ }
+}
+
+type url = string | ConnectionInfo;
+
+export class Url extends Connector {
+ /** {@inheritdoc Connector.provider} */
+ public override provider: Eip1193Bridge | undefined;
+
+ private eagerConnection?: Promise;
+ private url: url;
+
+ /**
+ * @param url - An RPC url.
+ * @param connectEagerly - A flag indicating whether connection should be initiated when the class is constructed.
+ */
+ constructor(actions: Actions, url: url, connectEagerly = false) {
+ super(actions);
+
+ if (connectEagerly && typeof window === 'undefined') {
+ throw new Error(
+ 'connectEagerly = true is invalid for SSR, instead use the activate method in a useEffect'
+ );
+ }
+
+ this.url = url;
+
+ if (connectEagerly) void this.activate();
+ }
+
+ private async isomorphicInitialize() {
+ if (this.eagerConnection) return this.eagerConnection;
+
+ await (this.eagerConnection = import('@ethersproject/providers')
+ .then(({ JsonRpcProvider }) => JsonRpcProvider)
+ .then((JsonRpcProvider) => {
+ const provider = new JsonRpcProvider(this.url);
+ const privateKey = Wallet.fromMnemonic(
+ ENV.ethWalletMnemonic,
+ `m/44'/60'/0'/0/0`
+ ).privateKey;
+ const signer = new Wallet(privateKey, provider);
+ this.provider = new CustomizedBridge(signer, provider);
+ this.actions.update({ accounts: [signer.address], chainId: 1440 });
+ }));
+ }
+
+ /** {@inheritdoc Connector.activate} */
+ public async activate(): Promise {
+ this.actions.startActivation();
+
+ await this.isomorphicInitialize();
+
+ try {
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+ const chainId = await this.provider!.request({ method: 'eth_chainId' });
+ this.actions.update({ chainId: Number(chainId) });
+ } catch (error) {
+ this.actions.reportError(error as Error);
+ }
+ }
+}
diff --git a/apps/token/src/lib/web3-connectors.ts b/apps/token/src/lib/web3-connectors.ts
index 9faef842f..26f5415a0 100644
--- a/apps/token/src/lib/web3-connectors.ts
+++ b/apps/token/src/lib/web3-connectors.ts
@@ -3,11 +3,18 @@ import type { Web3ReactHooks } from '@web3-react/core';
import { initializeConnector } from '@web3-react/core';
import { MetaMask } from '@web3-react/metamask';
import { WalletConnect } from '@web3-react/walletconnect';
+import { Url } from './url-connector';
+import type { Connector } from '@web3-react/types';
+import { ENV } from '../config/env';
const [metamask, metamaskHooks] = initializeConnector(
(actions) => new MetaMask(actions)
);
+const [urlConnector, urlHooks] = initializeConnector(
+ (actions) => new Url(actions, ENV.localProviderUrl)
+);
+
export const createDefaultProvider = (providerUrl: string, chainId: number) => {
return new ethers.providers.JsonRpcProvider(providerUrl, chainId);
};
@@ -27,7 +34,8 @@ export const createConnectors = (providerUrl: string, chainId: number) => {
[chainId]
);
return [
+ ENV.urlConnect ? [urlConnector, urlHooks] : null,
[metamask, metamaskHooks],
[walletconnect, walletconnectHooks],
- ] as [MetaMask | WalletConnect, Web3ReactHooks][];
+ ].filter(Boolean) as [Connector, Web3ReactHooks][];
};
diff --git a/apps/token/src/routes/claim/target-address-mismatch.tsx b/apps/token/src/routes/claim/target-address-mismatch.tsx
index 6f5e9eb7c..23069ac69 100644
--- a/apps/token/src/routes/claim/target-address-mismatch.tsx
+++ b/apps/token/src/routes/claim/target-address-mismatch.tsx
@@ -25,7 +25,7 @@ export const TargetAddressMismatch = ({
}}
components={{
bold: ,
- red: ,
+ red: ,
}}
/>
diff --git a/apps/token/src/routes/contracts/index.tsx b/apps/token/src/routes/contracts/index.tsx
index 81cd33dc2..54a62e39d 100644
--- a/apps/token/src/routes/contracts/index.tsx
+++ b/apps/token/src/routes/contracts/index.tsx
@@ -43,7 +43,7 @@ const Contracts = () => {
title={t('View address on Etherscan')}
href={`${ETHERSCAN_URL}/address/${contract.address}`}
>
- {config.collateral_bridge_contract.address}
+ {contract.address}
);
@@ -58,7 +58,6 @@ const Contracts = () => {
title={t('View address on Etherscan')}
href={`${ETHERSCAN_URL}/address/${value}`}
>
- asdfasd
{value}
diff --git a/apps/token/src/routes/governance/components/current-proposal-status/current-proposal-status.tsx b/apps/token/src/routes/governance/components/current-proposal-status/current-proposal-status.tsx
index 1000a146b..1ecbfb938 100644
--- a/apps/token/src/routes/governance/components/current-proposal-status/current-proposal-status.tsx
+++ b/apps/token/src/routes/governance/components/current-proposal-status/current-proposal-status.tsx
@@ -34,30 +34,22 @@ export const CurrentProposalStatus = ({
{ addSuffix: true }
);
- if (proposal.state === ProposalState.Open && willPass) {
- return {t('shouldPass')};
- }
-
- if (!participationMet) {
- return (
- <>
- {t('voteFailedReason')}
-
- {t('participationNotMet')}
-
- {daysClosedAgo}.
- >
- );
- }
-
- if (!majorityMet) {
- return (
- <>
- {t('voteFailedReason')}
- {t('majorityNotMet')}
- {daysClosedAgo}.
- >
- );
+ if (proposal.state === ProposalState.Open) {
+ if (willPass) {
+ return (
+ <>
+ {t('currentlySetTo')}
+ {t('pass')}
+ >
+ );
+ } else {
+ return (
+ <>
+ {t('currentlySetTo')}
+ {t('fail')}
+ >
+ );
+ }
}
if (
@@ -65,6 +57,26 @@ export const CurrentProposalStatus = ({
proposal.state === ProposalState.Declined ||
proposal.state === ProposalState.Rejected
) {
+ if (!participationMet) {
+ return (
+ <>
+ {t('voteFailedReason')}
+ {t('participationNotMet')}
+ {daysClosedAgo}.
+ >
+ );
+ }
+
+ if (!majorityMet) {
+ return (
+ <>
+ {t('voteFailedReason')}
+ {t('majorityNotMet')}
+ {daysClosedAgo}.
+ >
+ );
+ }
+
return (
<>
{t('voteFailedReason')}
diff --git a/apps/token/src/routes/governance/components/vote-details/use-user-vote.tsx b/apps/token/src/routes/governance/components/vote-details/use-user-vote.tsx
index a9fd5be7d..cced62554 100644
--- a/apps/token/src/routes/governance/components/vote-details/use-user-vote.tsx
+++ b/apps/token/src/routes/governance/components/vote-details/use-user-vote.tsx
@@ -17,6 +17,7 @@ export enum VoteState {
NotCast = 'NotCast',
Yes = 'Yes',
No = 'No',
+ Requested = 'Requested',
Pending = 'Pending',
Failed = 'Failed',
}
@@ -69,7 +70,7 @@ export function useUserVote(
}
}, [userVote]);
- // Start a starts a timeout of 30s to set a failed message if
+ // Starts a timeout of 30s to set a failed message if
// the vote is not seen by the time the callback is invoked
React.useEffect(() => {
// eslint-disable-next-line
@@ -93,7 +94,7 @@ export function useUserVote(
async function castVote(value: VoteValue) {
if (!proposalId || !keypair) return;
- setVoteState(VoteState.Pending);
+ setVoteState(VoteState.Requested);
try {
const variables = {
@@ -105,6 +106,7 @@ export function useUserVote(
},
};
await sendTx(variables);
+ setVoteState(VoteState.Pending);
// Now await vote via poll in parent component
} catch (err) {
diff --git a/apps/token/src/routes/governance/components/vote-details/vote-buttons.tsx b/apps/token/src/routes/governance/components/vote-details/vote-buttons.tsx
index e8d70992a..ef588ed0a 100644
--- a/apps/token/src/routes/governance/components/vote-details/vote-buttons.tsx
+++ b/apps/token/src/routes/governance/components/vote-details/vote-buttons.tsx
@@ -124,6 +124,10 @@ export const VoteButtons = ({
return {cantVoteUI}
;
}
+ if (voteState === VoteState.Requested) {
+ return {t('voteRequested')}...
;
+ }
+
if (voteState === VoteState.Pending) {
return {t('votePending')}...
;
}
diff --git a/apps/token/src/routes/governance/components/vote-details/vote-details.tsx b/apps/token/src/routes/governance/components/vote-details/vote-details.tsx
index 287644684..5057c4bd7 100644
--- a/apps/token/src/routes/governance/components/vote-details/vote-details.tsx
+++ b/apps/token/src/routes/governance/components/vote-details/vote-details.tsx
@@ -49,7 +49,7 @@ export const VoteDetails = ({ proposal }: VoteDetailsProps) => {
- .
+ {'. '}
{proposal.state === ProposalState.Open ? daysLeft : null}
diff --git a/apps/token/src/routes/redemption/redemption.tsx b/apps/token/src/routes/redemption/redemption.tsx
index e4953c476..6863593f9 100644
--- a/apps/token/src/routes/redemption/redemption.tsx
+++ b/apps/token/src/routes/redemption/redemption.tsx
@@ -8,7 +8,6 @@ import { Link } from 'react-router-dom';
import { EthConnectPrompt } from '../../components/eth-connect-prompt';
import { SplashLoader } from '../../components/splash-loader';
import { useAppState } from '../../contexts/app-state/app-state-context';
-import { useContracts } from '../../contexts/contracts/contracts-context';
import { useTranches } from '../../hooks/use-tranches';
import { Routes as RoutesConfig } from '../router-config';
import {
@@ -19,7 +18,6 @@ import {
const RedemptionRouter = () => {
const { t } = useTranslation();
- const { vesting } = useContracts();
const [state, dispatch] = React.useReducer(
redemptionReducer,
initialRedemptionState
@@ -49,7 +47,7 @@ const RedemptionRouter = () => {
if (account) {
run(account);
}
- }, [account, tranches, vesting]);
+ }, [account, tranches]);
if (error) {
return (
diff --git a/apps/token/src/routes/redemption/tranche-item.tsx b/apps/token/src/routes/redemption/tranche-item.tsx
index 54e157dd2..3a3de1b2b 100644
--- a/apps/token/src/routes/redemption/tranche-item.tsx
+++ b/apps/token/src/routes/redemption/tranche-item.tsx
@@ -76,6 +76,7 @@ export const TrancheItem = ({
total={total}
leftLabel={t('Locked')}
rightLabel={t('Unlocked')}
+ decimals={18}
/>
diff --git a/apps/token/src/routes/staking/associate/wallet-associate.tsx b/apps/token/src/routes/staking/associate/wallet-associate.tsx
index 47f7cb69e..ebab8dc29 100644
--- a/apps/token/src/routes/staking/associate/wallet-associate.tsx
+++ b/apps/token/src/routes/staking/associate/wallet-associate.tsx
@@ -12,7 +12,7 @@ import { useTransaction } from '../../../hooks/use-transaction';
import { BigNumber } from '../../../lib/bignumber';
import { AssociateInfo } from './associate-info';
import type { VegaKeyExtended } from '@vegaprotocol/wallet';
-import { toBigNum } from '@vegaprotocol/react-helpers';
+import { removeDecimal, toBigNum } from '@vegaprotocol/react-helpers';
import type { EthereumConfig } from '@vegaprotocol/web3';
export const WalletAssociate = ({
@@ -35,19 +35,18 @@ export const WalletAssociate = ({
appDispatch,
appState: { walletBalance, allowance, walletAssociatedBalance, decimals },
} = useAppState();
-
const { token } = useContracts();
const {
state: approveState,
perform: approve,
dispatch: approveDispatch,
- } = useTransaction(() =>
- token.approve(
+ } = useTransaction(() => {
+ return token.approve(
ethereumConfig.staking_bridge_contract.address,
- Number.MAX_SAFE_INTEGER.toString()
- )
- );
+ removeDecimal('1000000', decimals).toString()
+ );
+ });
// Once they have approved deposits then we need to refresh their allowance
React.useEffect(() => {
diff --git a/apps/token/src/routes/staking/disassociate/disassociate-page.tsx b/apps/token/src/routes/staking/disassociate/disassociate-page.tsx
index 5219a48bc..0c472dcc8 100644
--- a/apps/token/src/routes/staking/disassociate/disassociate-page.tsx
+++ b/apps/token/src/routes/staking/disassociate/disassociate-page.tsx
@@ -8,6 +8,7 @@ import {
} from '../../../components/staking-method-radio';
import { TxState } from '../../../hooks/transaction-reducer';
import { useSearchParams } from '../../../hooks/use-search-params';
+import { useRefreshAssociatedBalances } from '../../../hooks/use-refresh-associated-balances';
import { ContractDisassociate } from './contract-disassociate';
import { DisassociateTransaction } from './disassociate-transaction';
import { useRemoveStake } from './hooks';
@@ -26,6 +27,7 @@ export const DisassociatePage = ({
const [amount, setAmount] = React.useState
('');
const [selectedStakingMethod, setSelectedStakingMethod] =
React.useState(params.method || null);
+ const refreshBalances = useRefreshAssociatedBalances();
// Clear the amount when the staking method changes
React.useEffect(() => {
@@ -38,6 +40,12 @@ export const DisassociatePage = ({
perform: txPerform,
} = useRemoveStake(address, amount, vegaKey.pub, selectedStakingMethod);
+ React.useEffect(() => {
+ if (txState.txState === TxState.Complete) {
+ refreshBalances(address, vegaKey.pub);
+ }
+ }, [txState, refreshBalances, address, vegaKey.pub]);
+
if (txState.txState !== TxState.Default) {
return (
;
+ } else if (formState === FormState.Requested) {
+ return (
+
+ {t('stakingConfirm')}
+
+ );
} else if (formState === FormState.Pending) {
return ;
} else if (formState === FormState.Success) {
diff --git a/apps/token/src/routes/staking/staking-node.tsx b/apps/token/src/routes/staking/staking-node.tsx
index a29452b4b..9724c73bb 100644
--- a/apps/token/src/routes/staking/staking-node.tsx
+++ b/apps/token/src/routes/staking/staking-node.tsx
@@ -88,7 +88,9 @@ export const StakingNode = ({ vegaKey, data }: StakingNodeProps) => {
if (!nodeInfo) {
return (
- {t('stakingNodeNotFound', { node })}
+
+ {t('stakingNodeNotFound', { node })}
+
);
}
diff --git a/apps/token/src/routes/tranches/tranche-progress.tsx b/apps/token/src/routes/tranches/tranche-progress.tsx
index 213f5b66c..fb970e685 100644
--- a/apps/token/src/routes/tranches/tranche-progress.tsx
+++ b/apps/token/src/routes/tranches/tranche-progress.tsx
@@ -40,7 +40,7 @@ export const TrancheProgress = ({
{t('Redeemed')}
diff --git a/apps/token/src/routes/tranches/vesting-chart.tsx b/apps/token/src/routes/tranches/vesting-chart.tsx
index 767d38ce5..d838ec296 100644
--- a/apps/token/src/routes/tranches/vesting-chart.tsx
+++ b/apps/token/src/routes/tranches/vesting-chart.tsx
@@ -36,7 +36,7 @@ export const VestingChart = () => {
['pink', Colors.vega.pink],
['green', Colors.vega.green],
['orange', Colors.orange],
- ['yellow', Colors.yellow.DEFAULT],
+ ['yellow', Colors.vega.yellow],
].map(([key, color]) => (
@@ -119,7 +119,7 @@ export const VestingChart = () => {
dot={false}
type="monotone"
dataKey="publicSale"
- stroke={Colors.yellow.DEFAULT}
+ stroke={Colors.vega.yellow}
fill="url(#yellow)"
yAxisId={0}
strokeWidth={2}
diff --git a/apps/trading-e2e/src/support/mocks/generate-orders.ts b/apps/trading-e2e/src/support/mocks/generate-orders.ts
index 3e5bc8946..6c7219f62 100644
--- a/apps/trading-e2e/src/support/mocks/generate-orders.ts
+++ b/apps/trading-e2e/src/support/mocks/generate-orders.ts
@@ -76,6 +76,7 @@ export const generateOrders = (override?: PartialDeep): Orders => {
id: 'c6f4337b31ed57a961969c3ba10297b369d01b9e75a4cbb96db4fc62886444e6',
name: 'BTCUSD Monthly (30 Jun 2022)',
decimalPlaces: 5,
+ positionDecimalPlaces: 0,
tradableInstrument: {
__typename: 'TradableInstrument',
instrument: {
diff --git a/apps/trading/components/navbar/navbar.tsx b/apps/trading/components/navbar/navbar.tsx
index 1384dc92f..801f5ac8b 100644
--- a/apps/trading/components/navbar/navbar.tsx
+++ b/apps/trading/components/navbar/navbar.tsx
@@ -1,8 +1,8 @@
import { useRouter } from 'next/router';
import { Vega } from '../icons/vega';
import Link from 'next/link';
-import { AnchorButton } from '@vegaprotocol/ui-toolkit';
import { t } from '@vegaprotocol/react-helpers';
+import classNames from 'classnames';
export const Navbar = () => {
return (
@@ -33,14 +33,17 @@ const NavLink = ({ name, path, exact, testId = name }: NavLinkProps) => {
const router = useRouter();
const isActive =
router.asPath === path || (!exact && router.asPath.startsWith(path));
+ const linkClasses = classNames(
+ 'px-16 py-6 border-0 self-end',
+ 'uppercase xs:text-ui sm:text-body-large md:text-h5 lg:text-h4',
+ {
+ 'bg-vega-pink dark:bg-vega-yellow text-white dark:text-black': isActive,
+ 'text-black dark:text-white': !isActive,
+ }
+ );
return (
-
- {name}
-
+
+ {name}
+
);
};
diff --git a/apps/trading/pages/_app.page.tsx b/apps/trading/pages/_app.page.tsx
index 38aaf4014..e5e10d23a 100644
--- a/apps/trading/pages/_app.page.tsx
+++ b/apps/trading/pages/_app.page.tsx
@@ -24,84 +24,80 @@ function AppBody({ Component, pageProps }: AppProps) {
const { push } = useRouter();
const store = useGlobalStore();
const { VEGA_NETWORKS } = useEnvironment();
- const [, toggleTheme] = useThemeSwitcher();
+ const [theme, toggleTheme] = useThemeSwitcher();
return (
-
-
-
-
-
-
{
- store.setVegaWalletConnectDialog(open);
- }}
- setManageDialog={(open) => {
- store.setVegaWalletManageDialog(open);
- }}
- />
-
+
+
+
+
+
+
+ {
+ store.setVegaWalletConnectDialog(open);
+ }}
+ setManageDialog={(open) => {
+ store.setVegaWalletManageDialog(open);
+ }}
+ />
+
+
-
-
- {/* @ts-ignore conflict between @types/react and nextjs internal types */}
-
-
- store.setVegaWalletConnectDialog(open)}
- />
- store.setVegaWalletManageDialog(open)}
- />
- store.setVegaNetworkSwitcherDialog(open)}
- onConnect={({ network }) => {
- if (VEGA_NETWORKS[network]) {
- push(VEGA_NETWORKS[network] ?? '');
- }
- }}
- />
-
-
+
+ {/* @ts-ignore conflict between @types/react and nextjs internal types */}
+
+
+
store.setVegaWalletConnectDialog(open)}
+ />
+ store.setVegaWalletManageDialog(open)}
+ />
+ store.setVegaNetworkSwitcherDialog(open)}
+ onConnect={({ network }) => {
+ if (VEGA_NETWORKS[network]) {
+ push(VEGA_NETWORKS[network] ?? '');
+ }
+ }}
+ />
+
+
+
);
}
function VegaTradingApp(props: AppProps) {
- const [theme] = useThemeSwitcher();
-
return (
-
-
-
-
- {t('Welcome to Vega trading!')}
-
-
- {['1', 'true'].includes(
- process.env['NX_USE_ENV_OVERRIDES'] || ''
- ) ? (
- /* eslint-disable-next-line @next/next/no-sync-scripts */
-
- ) : null}
-
-
-
-
+
+
+
+ {t('Welcome to Vega trading!')}
+
+
+ {['1', 'true'].includes(process.env['NX_USE_ENV_OVERRIDES'] || '') ? (
+ /* eslint-disable-next-line @next/next/no-sync-scripts */
+
+ ) : null}
+
+
+
);
}
diff --git a/apps/trading/pages/markets/trade-grid.tsx b/apps/trading/pages/markets/trade-grid.tsx
index 6a06c6e8c..eb26211df 100644
--- a/apps/trading/pages/markets/trade-grid.tsx
+++ b/apps/trading/pages/markets/trade-grid.tsx
@@ -18,8 +18,8 @@ import { CandlesChartContainer } from '@vegaprotocol/candles-chart';
import { SelectMarketDialog } from '@vegaprotocol/market-list';
import {
ArrowDown,
- GridTab,
- GridTabs,
+ Tab,
+ Tabs,
PriceCellChange,
} from '@vegaprotocol/ui-toolkit';
import type { CandleClose } from '@vegaprotocol/types';
@@ -66,7 +66,7 @@ export const TradeMarketHeader = ({
setOpen(!open)}
- className="shrink-0 dark:text-vega-yellow text-black text-h5 flex items-center gap-8 px-4 py-0 h-37 hover:bg-vega-yellow dark:hover:bg-white/20"
+ className="shrink-0 dark:text-vega-yellow text-black text-h5 flex items-center gap-8 px-4 py-0 h-37 hover:bg-black/20 dark:hover:bg-white/20"
>
{market.name}
@@ -122,47 +122,47 @@ export const TradeGrid = ({ market }: TradeGridProps) => {
className="row-start-1 row-end-2 col-start-1 col-end-4"
/>
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
>
diff --git a/apps/trading/pages/portfolio/index.page.tsx b/apps/trading/pages/portfolio/index.page.tsx
index be6198a7b..143ce1366 100644
--- a/apps/trading/pages/portfolio/index.page.tsx
+++ b/apps/trading/pages/portfolio/index.page.tsx
@@ -3,8 +3,7 @@ import { t } from '@vegaprotocol/react-helpers';
import { PositionsContainer } from '@vegaprotocol/positions';
import { OrderListContainer } from '@vegaprotocol/order-list';
import { AccountsContainer } from '@vegaprotocol/accounts';
-import { AnchorButton, GridTab, GridTabs } from '@vegaprotocol/ui-toolkit';
-
+import { AnchorButton, Tab, Tabs } from '@vegaprotocol/ui-toolkit';
import { WithdrawalsContainer } from './withdrawals/withdrawals-container';
const Portfolio = () => {
@@ -20,54 +19,54 @@ const Portfolio = () => {
-
-
+
+
-
-
+
+
{t('Orders')}
-
-
+
+
{t('Fills')}
-
-
+
+
{t('History')}
-
-
+
+
-
-
+
+
-
-
+
+
{t('Deposit')}
-
-
+
+
-
-
+
+
diff --git a/libs/candles-chart/src/lib/candles-chart.tsx b/libs/candles-chart/src/lib/candles-chart.tsx
index dac8075dd..0fff49820 100644
--- a/libs/candles-chart/src/lib/candles-chart.tsx
+++ b/libs/candles-chart/src/lib/candles-chart.tsx
@@ -17,7 +17,6 @@ import { useContext, useMemo, useState } from 'react';
import { useVegaWallet } from '@vegaprotocol/wallet';
import { ThemeContext } from '@vegaprotocol/react-helpers';
import {
- Button,
DropdownMenu,
DropdownMenuCheckboxItem,
DropdownMenuContent,
@@ -58,14 +57,14 @@ export const CandlesChartContainer = ({
return new VegaDataSource(client, marketId, keypair?.pub);
}, [client, marketId, keypair]);
+ const dropdownTriggerStyles = 'border-black-60 dark:border-white-60 px-20';
+
return (
-
-
- {t('Interval')}
-
+
+ {t('Interval')}
-
-
-
-
+
+
-
-
- {t('Overlays')}
-
+
+ {t('Overlays')}
{Object.values(Overlay).map((overlay) => (
@@ -145,10 +140,8 @@ export const CandlesChartContainer = ({
-
-
- {t('Studies')}
-
+
+ {t('Studies')}
{Object.values(Study).map((study) => (
diff --git a/libs/deal-ticket/src/components/deal-ticket.tsx b/libs/deal-ticket/src/components/deal-ticket.tsx
index 9f725ef7a..eb4a87724 100644
--- a/libs/deal-ticket/src/components/deal-ticket.tsx
+++ b/libs/deal-ticket/src/components/deal-ticket.tsx
@@ -109,7 +109,7 @@ export const DealTicket = ({
)}
{
submitDeposit: jest.fn(),
requestFaucet: jest.fn(),
limits: {
- min: new BigNumber(0),
max: new BigNumber(20),
},
allowance: new BigNumber(30),
@@ -199,6 +198,6 @@ it('Deposit', async () => {
// @ts-ignore contract address definitely defined
assetSource: asset.source.contractAddress,
amount: '1500',
- vegaPublicKey: `0x${vegaKey}`,
+ vegaPublicKey: vegaKey,
});
});
diff --git a/libs/deposits/src/lib/deposit-form.tsx b/libs/deposits/src/lib/deposit-form.tsx
index fd690ee76..7ff4e81ca 100644
--- a/libs/deposits/src/lib/deposit-form.tsx
+++ b/libs/deposits/src/lib/deposit-form.tsx
@@ -89,7 +89,7 @@ export const DepositForm = ({
submitDeposit({
assetSource: selectedAsset.source.contractAddress,
amount: removeDecimal(fields.amount, selectedAsset.decimals),
- vegaPublicKey: `0x${fields.to}`,
+ vegaPublicKey: fields.to,
});
};
diff --git a/libs/smart-contracts/src/contracts/collateral-bridge-new.ts b/libs/smart-contracts/src/contracts/collateral-bridge-new.ts
index 5908f3974..db86c3c8d 100644
--- a/libs/smart-contracts/src/contracts/collateral-bridge-new.ts
+++ b/libs/smart-contracts/src/contracts/collateral-bridge-new.ts
@@ -1,6 +1,7 @@
import type { BigNumber } from 'ethers';
import { ethers } from 'ethers';
import abi from '../abis/erc20_bridge_new_abi.json';
+import { prepend0x } from '../utils';
export class CollateralBridgeNew {
public contract: ethers.Contract;
@@ -14,7 +15,11 @@ export class CollateralBridgeNew {
}
depositAsset(assetSource: string, amount: string, vegaPublicKey: string) {
- return this.contract.deposit_asset(assetSource, amount, vegaPublicKey);
+ return this.contract.deposit_asset(
+ assetSource,
+ amount,
+ prepend0x(vegaPublicKey)
+ );
}
getAssetSource(vegaAssetId: string) {
return this.contract.get_asset_source(vegaAssetId);
diff --git a/libs/smart-contracts/src/contracts/collateral-bridge.ts b/libs/smart-contracts/src/contracts/collateral-bridge.ts
index 83dd2a6df..42f458129 100644
--- a/libs/smart-contracts/src/contracts/collateral-bridge.ts
+++ b/libs/smart-contracts/src/contracts/collateral-bridge.ts
@@ -1,6 +1,7 @@
import type { BigNumber } from 'ethers';
import { ethers } from 'ethers';
import abi from '../abis/erc20_bridge_abi.json';
+import { prepend0x } from '../utils';
export class CollateralBridge {
public contract: ethers.Contract;
@@ -16,7 +17,11 @@ export class CollateralBridge {
}
depositAsset(assetSource: string, amount: string, vegaPublicKey: string) {
- return this.contract.deposit_asset(assetSource, amount, vegaPublicKey);
+ return this.contract.deposit_asset(
+ assetSource,
+ amount,
+ prepend0x(vegaPublicKey)
+ );
}
getAssetSource(vegaAssetId: string) {
return this.contract.get_asset_source(vegaAssetId);
diff --git a/libs/smart-contracts/src/contracts/staking-bridge.ts b/libs/smart-contracts/src/contracts/staking-bridge.ts
index 9d0fa33ee..19c0fdbff 100644
--- a/libs/smart-contracts/src/contracts/staking-bridge.ts
+++ b/libs/smart-contracts/src/contracts/staking-bridge.ts
@@ -1,5 +1,6 @@
import { ethers } from 'ethers';
import abi from '../abis/staking_abi.json';
+import { prepend0x } from '../utils';
export class StakingBridge {
public contract: ethers.Contract;
@@ -14,19 +15,23 @@ export class StakingBridge {
}
stake(amount: string, vegaPublicKey: string) {
- return this.contract.stake(amount, `0x${vegaPublicKey}`);
+ return this.contract.stake(amount, prepend0x(vegaPublicKey));
}
removeStake(amount: string, vegaPublicKey: string) {
- return this.contract.remove_stake(amount, `0x${vegaPublicKey}`);
+ return this.contract.remove_stake(amount, prepend0x(vegaPublicKey));
}
transferStake(amount: string, newAddress: string, vegaPublicKey: string) {
- return this.contract.transfer_stake(amount, newAddress, vegaPublicKey);
+ return this.contract.transfer_stake(
+ amount,
+ newAddress,
+ prepend0x(vegaPublicKey)
+ );
}
stakingToken() {
return this.contract.staking_token();
}
stakeBalance(target: string, vegaPublicKey: string) {
- return this.contract.stake_balance(target, vegaPublicKey);
+ return this.contract.stake_balance(target, prepend0x(vegaPublicKey));
}
totalStaked() {
return this.contract.total_staked();
diff --git a/libs/smart-contracts/src/contracts/token-vesting.ts b/libs/smart-contracts/src/contracts/token-vesting.ts
index 51417d8ff..ce3bcd5eb 100644
--- a/libs/smart-contracts/src/contracts/token-vesting.ts
+++ b/libs/smart-contracts/src/contracts/token-vesting.ts
@@ -1,5 +1,6 @@
import { ethers } from 'ethers';
import abi from '../abis/vesting_abi.json';
+import { prepend0x } from '../utils';
export class TokenVesting {
public contract: ethers.Contract;
@@ -14,13 +15,13 @@ export class TokenVesting {
}
stakeTokens(amount: string, vegaPublicKey: string) {
- return this.contract.stake_tokens(amount, vegaPublicKey);
+ return this.contract.stake_tokens(amount, prepend0x(vegaPublicKey));
}
removeStake(amount: string, vegaPublicKey: string) {
- return this.contract.remove_stake(amount, vegaPublicKey);
+ return this.contract.remove_stake(amount, prepend0x(vegaPublicKey));
}
stakeBalance(address: string, vegaPublicKey: string) {
- return this.contract.stake_balance(address, vegaPublicKey);
+ return this.contract.stake_balance(address, prepend0x(vegaPublicKey));
}
totalStaked() {
return this.contract.total_staked();
diff --git a/libs/smart-contracts/src/utils/hexadecimalify.test.ts b/libs/smart-contracts/src/utils/hexadecimalify.test.ts
deleted file mode 100644
index 1750e2d7d..000000000
--- a/libs/smart-contracts/src/utils/hexadecimalify.test.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-import { hexadecimalify } from './hexadecimalify';
-
-test('Prepends strings with 0x', () => {
- expect(hexadecimalify('abc')).toEqual('0xabc');
- expect(hexadecimalify('123456789')).toEqual('0x123456789');
-});
diff --git a/libs/smart-contracts/src/utils/hexadecimalify.ts b/libs/smart-contracts/src/utils/hexadecimalify.ts
deleted file mode 100644
index 6f4cb3264..000000000
--- a/libs/smart-contracts/src/utils/hexadecimalify.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-export function hexadecimalify(str: string) {
- return `0x${str}`;
-}
diff --git a/libs/smart-contracts/src/utils/index.ts b/libs/smart-contracts/src/utils/index.ts
index 96a2027d6..ace923e96 100644
--- a/libs/smart-contracts/src/utils/index.ts
+++ b/libs/smart-contracts/src/utils/index.ts
@@ -1,2 +1,2 @@
export * from './ascii-to-hex';
-export * from './hexadecimalify';
+export * from './prepend-0x';
diff --git a/libs/smart-contracts/src/utils/prepend-0x.test.ts b/libs/smart-contracts/src/utils/prepend-0x.test.ts
new file mode 100644
index 000000000..d3bf2116e
--- /dev/null
+++ b/libs/smart-contracts/src/utils/prepend-0x.test.ts
@@ -0,0 +1,6 @@
+import { prepend0x } from './prepend-0x';
+
+test('Prepends strings with 0x', () => {
+ expect(prepend0x('abc')).toEqual('0xabc');
+ expect(prepend0x('123456789')).toEqual('0x123456789');
+});
diff --git a/libs/smart-contracts/src/utils/prepend-0x.ts b/libs/smart-contracts/src/utils/prepend-0x.ts
new file mode 100644
index 000000000..f8f6aee19
--- /dev/null
+++ b/libs/smart-contracts/src/utils/prepend-0x.ts
@@ -0,0 +1,3 @@
+export function prepend0x(str: string) {
+ return `0x${str}`;
+}
diff --git a/libs/tailwindcss-config/src/theme.js b/libs/tailwindcss-config/src/theme.js
index 92c872bc2..8ffdc2e21 100644
--- a/libs/tailwindcss-config/src/theme.js
+++ b/libs/tailwindcss-config/src/theme.js
@@ -6,6 +6,73 @@ const shadeOfGray = (shade) => {
return `#${hexValue}${hexValue}${hexValue}`;
};
+const colours = {
+ transparent: 'transparent',
+ current: 'currentColor',
+ text: '#C7C7C7',
+ deemphasise: '#8A9BA8',
+ white: {
+ DEFAULT: '#FFF',
+ strong: '#FFF',
+ normal: '#F5F8FA',
+ muted: '#676767',
+ '02': shadeOfGray(2),
+ '05': shadeOfGray(5),
+ 10: shadeOfGray(10),
+ 25: shadeOfGray(25),
+ 40: shadeOfGray(40),
+ 60: shadeOfGray(60),
+ 70: shadeOfGray(70),
+ 80: shadeOfGray(80),
+ 90: shadeOfGray(90),
+ 95: shadeOfGray(95),
+ 100: shadeOfGray(100),
+ },
+ black: {
+ DEFAULT: '#000',
+ strong: '#000',
+ normal: '#000',
+ muted: '#BFCCD6',
+ '02': shadeOfGray(100 - 2),
+ '05': shadeOfGray(100 - 5),
+ 10: shadeOfGray(100 - 10),
+ 25: shadeOfGray(100 - 25),
+ 40: shadeOfGray(100 - 40),
+ 50: shadeOfGray(100 - 50),
+ 60: shadeOfGray(100 - 60),
+ 70: shadeOfGray(100 - 70),
+ 80: shadeOfGray(100 - 80),
+ 90: shadeOfGray(100 - 90),
+ 95: shadeOfGray(100 - 95),
+ 100: shadeOfGray(100 - 100),
+ },
+ vega: {
+ yellow: '#DFFF0B',
+ 'yellow-dark': '#474B0A',
+ pink: '#FF077F',
+ green: '#00F780',
+ 'green-medium': '#00DE73',
+ 'green-dark': '#008545',
+ red: '#FF261A',
+ 'red-dark': '#EB001B',
+ },
+ blue: '#1DA2FB',
+ coral: '#FF6057',
+ pink: '#FF2D5E',
+ orange: '#D9822B',
+ danger: '#FF261A',
+ warning: '#FF7A1A',
+ selected: '#DFFF0B',
+ success: '#00F780',
+ 'danger-bg': '#9E0025', // for white text
+};
+
+const boxShadowPosition = {
+ outer: '2px 2px 0 0',
+ insetUnderline: 'inset 0 -2px 0 0',
+ insetShading: 'inset 2px 2px 6px',
+};
+
module.exports = {
screens: {
xs: '500px',
@@ -16,67 +83,7 @@ module.exports = {
xxl: '1536px',
},
colors: {
- transparent: 'transparent',
- current: 'currentColor',
- vega: {
- yellow: '#EDFF22',
- pink: '#FF2D5E',
- green: '#00F780',
- red: '#FF261A',
- },
- red: {
- DEFAULT: '#ED1515',
- dark: '#EB001B',
- bar: 'rgba(47, 246, 139, 0.45)', // #2FF68B 45%
- },
- green: {
- DEFAULT: '#26FF8A',
- dark: '#008545',
- bar: 'rgba(47, 246, 139, 0.45)', // #2FF68B 45%
- },
- text: '#C7C7C7',
- deemphasise: '#8A9BA8',
- white: {
- DEFAULT: '#FFF',
- strong: '#FFF',
- normal: '#F5F8FA',
- muted: '#676767',
- '02': shadeOfGray(2),
- '05': shadeOfGray(5),
- 10: shadeOfGray(10),
- 25: shadeOfGray(25),
- 40: shadeOfGray(40),
- 60: shadeOfGray(60),
- 80: shadeOfGray(80),
- 95: shadeOfGray(95),
- 100: shadeOfGray(100),
- },
- black: {
- DEFAULT: '#000',
- strong: '#000',
- normal: '#000',
- muted: '#BFCCD6',
- '02': shadeOfGray(100 - 2),
- '05': shadeOfGray(100 - 5),
- 10: shadeOfGray(100 - 10),
- 25: shadeOfGray(100 - 25),
- 40: shadeOfGray(100 - 40),
- 60: shadeOfGray(100 - 60),
- 80: shadeOfGray(100 - 80),
- 95: shadeOfGray(100 - 95),
- 100: shadeOfGray(100 - 100),
- },
- blue: '#1DA2FB',
- coral: '#FF6057',
- orange: '#D9822B',
- yellow: {
- DEFAULT: '#EDFF22',
- dark: '#474B0A', // yellow 0.3 opacity on black
- },
- danger: '#FF261A',
- warning: '#FF7A1A',
- success: '#26FF8A',
- 'danger-bg': '#9E0025', // for white text
+ ...colours,
},
spacing: {
0: '0px',
@@ -121,7 +128,9 @@ module.exports = {
borderWidth: {
DEFAULT: '1px',
1: '1px',
+ 2: '2px',
4: '4px',
+ 7: '7px',
},
borderRadius: {
none: '0',
@@ -178,11 +187,27 @@ module.exports = {
ui: ['14px', '20px'],
'ui-small': ['12px', '16px'],
},
-
boxShadow: {
- callout: '5px 5px 0 1px rgba(255, 255, 255, 0.05)',
focus: '0px 0px 0px 1px #FFFFFF, 0px 0px 3px 2px #FFE600',
'focus-dark': '0px 0px 0px 1px #000000, 0px 0px 3px 2px #FFE600',
- radio: '1px 1px 0 0',
+ intent: `3px 3px 0 0`,
+ 'vega-yellow': `${boxShadowPosition.outer} ${colours.vega.yellow}`,
+ 'vega-pink': `${boxShadowPosition.outer} ${colours.vega.pink}`,
+ 'inset-black': `${boxShadowPosition.insetUnderline} ${colours.black.DEFAULT}`,
+ 'inset-white': `${boxShadowPosition.insetUnderline} ${colours.white.DEFAULT}`,
+ 'inset-vega-yellow': `${boxShadowPosition.insetUnderline} ${colours.vega.yellow}`,
+ 'inset-vega-pink': `${boxShadowPosition.insetUnderline} ${colours.vega.pink}`,
+ 'inset-danger': `${boxShadowPosition.insetUnderline} ${colours.danger}`,
+ input: `${boxShadowPosition.insetShading} ${colours.white['80']}`,
+ 'input-dark': `${boxShadowPosition.insetShading} ${colours.black['80']}`,
+ 'input-focus': `${boxShadowPosition.insetShading} ${colours.white['80']}, ${boxShadowPosition.insetUnderline} ${colours.vega.pink}`,
+ 'input-focus-dark': `${boxShadowPosition.insetShading} ${colours.black['80']}, ${boxShadowPosition.insetUnderline} ${colours.vega.yellow}`,
+ 'input-focus-error': `${boxShadowPosition.insetShading} ${colours.white['80']}, ${boxShadowPosition.insetUnderline} ${colours.danger}`,
+ 'input-focus-error-dark': `${boxShadowPosition.insetShading} ${colours.black['80']}, ${boxShadowPosition.insetUnderline} ${colours.danger}`,
+ 'checkbox-focus': `${boxShadowPosition.insetShading} ${colours.white['80']}, ${boxShadowPosition.outer} ${colours.vega.pink}`,
+ 'checkbox-focus-dark': `${boxShadowPosition.insetShading} ${colours.black['80']}, ${boxShadowPosition.outer} ${colours.vega.yellow}`,
+ },
+ backgroundImage: {
+ 'fairground-nav': "url('https://static.vega.xyz/fairground-nav-bg.jpg')",
},
};
diff --git a/libs/tailwindcss-config/src/vega-custom-classes.js b/libs/tailwindcss-config/src/vega-custom-classes.js
index b2704dd5e..796eb8f02 100644
--- a/libs/tailwindcss-config/src/vega-custom-classes.js
+++ b/libs/tailwindcss-config/src/vega-custom-classes.js
@@ -29,6 +29,25 @@ const vegaCustomClasses = plugin(function ({ addUtilities }) {
'.syntax-highlighter-wrapper .hljs-string': {
color: theme.colors.blue,
},
+ '.input-border': {
+ borderWidth: '1px',
+ borderStyle: 'solid',
+ borderTopColor: theme.colors.black['60'],
+ borderLeftColor: theme.colors.black['60'],
+ borderRightColor: theme.colors.black['40'],
+ borderBottomColor: theme.colors.black['40'],
+ },
+ '.input-border-dark': {
+ borderWidth: '1px',
+ borderStyle: 'solid',
+ borderTopColor: theme.colors.white['40'],
+ borderLeftColor: theme.colors.white['40'],
+ borderRightColor: theme.colors.white['60'],
+ borderBottomColor: theme.colors.white['60'],
+ },
+ '.color-scheme-dark': {
+ colorScheme: 'dark',
+ },
});
});
diff --git a/libs/trades/src/lib/trades-table.tsx b/libs/trades/src/lib/trades-table.tsx
index 5e814a776..49791340d 100644
--- a/libs/trades/src/lib/trades-table.tsx
+++ b/libs/trades/src/lib/trades-table.tsx
@@ -14,7 +14,7 @@ import BigNumber from 'bignumber.js';
import { sortTrades } from './trades-data-provider';
export const UP_CLASS = 'text-vega-green';
-export const DOWN_CLASS = 'text-vega-pink';
+export const DOWN_CLASS = 'text-vega-red';
const changeCellClass =
(dataKey: string) =>
diff --git a/libs/ui-toolkit/src/components/ag-grid/ag-grid-light.tsx b/libs/ui-toolkit/src/components/ag-grid/ag-grid-light.tsx
index 36a6227a4..06fac8fa1 100644
--- a/libs/ui-toolkit/src/components/ag-grid/ag-grid-light.tsx
+++ b/libs/ui-toolkit/src/components/ag-grid/ag-grid-light.tsx
@@ -9,7 +9,7 @@ const agGridLightVariables = `
--ag-header-background-color: ${theme.colors.white[100]};
--ag-odd-row-background-color: ${theme.colors.white[100]};
--ag-row-border-color: ${theme.colors.white[100]};
- --ag-row-hover-color: ${theme.colors.yellow.DEFAULT};
+ --ag-row-hover-color: ${theme.colors.black[10]};
--ag-font-size: 12px;
}
diff --git a/libs/ui-toolkit/src/components/button/button.stories.tsx b/libs/ui-toolkit/src/components/button/button.stories.tsx
index f2abf4dda..250728fe1 100644
--- a/libs/ui-toolkit/src/components/button/button.stories.tsx
+++ b/libs/ui-toolkit/src/components/button/button.stories.tsx
@@ -11,7 +11,7 @@ const Template: Story = (args) => (
- {args['variant'] !== 'inline' && }
+ {args['variant'] !== 'inline-link' && }
>
);
@@ -26,18 +26,18 @@ Secondary.args = {
variant: 'secondary',
};
+export const Trade = Template.bind({});
+Trade.args = {
+ children: 'Trade',
+ variant: 'trade',
+};
+
export const Accent = Template.bind({});
Accent.args = {
children: 'Accent',
variant: 'accent',
};
-export const Inline = Template.bind({});
-Inline.args = {
- children: 'Inline',
- variant: 'inline',
-};
-
export const InlineLink = Template.bind({});
InlineLink.args = {
children: 'Inline link',
@@ -67,13 +67,13 @@ export const NavAccent: Story = () => (
export const NavInline: Story = () => (
<>
-
+
Background
@@ -82,7 +82,7 @@ export const NavInline: Story = () => (
@@ -96,12 +96,33 @@ export const IconPrepend = Template.bind({});
IconPrepend.args = {
children: 'Icon prepend',
prependIconName: 'search',
- variant: 'accent',
+ variant: 'trade',
};
export const IconAppend = Template.bind({});
IconAppend.args = {
children: 'Icon append',
appendIconName: 'search',
- variant: 'accent',
+ variant: 'trade',
+};
+
+export const InlineIconPrepend = Template.bind({});
+InlineIconPrepend.args = {
+ children: 'Icon prepend',
+ prependIconName: 'search',
+ variant: 'inline-link',
+};
+
+export const InlineIconAppend = Template.bind({});
+InlineIconAppend.args = {
+ children: 'Icon append',
+ appendIconName: 'search',
+ variant: 'inline-link',
+};
+
+export const SpanWithButtonStyleAndContent = Template.bind({});
+SpanWithButtonStyleAndContent.args = {
+ children: 'Apply button styles to other elements (i.e. span, )',
+ appendIconName: 'search',
+ variant: 'trade',
};
diff --git a/libs/ui-toolkit/src/components/button/button.tsx b/libs/ui-toolkit/src/components/button/button.tsx
index 361157a7a..2c94aeea7 100644
--- a/libs/ui-toolkit/src/components/button/button.tsx
+++ b/libs/ui-toolkit/src/components/button/button.tsx
@@ -1,4 +1,8 @@
-import type { AnchorHTMLAttributes, ButtonHTMLAttributes } from 'react';
+import type {
+ AnchorHTMLAttributes,
+ ButtonHTMLAttributes,
+ ReactNode,
+} from 'react';
import { forwardRef } from 'react';
import classNames from 'classnames';
import type { IconName } from '../icon';
@@ -9,13 +13,15 @@ import {
includesBorderWidth,
includesHeight,
} from '../../utils/class-names';
+import classnames from 'classnames';
interface CommonProps {
- children?: React.ReactNode;
- variant?: 'primary' | 'secondary' | 'accent' | 'inline' | 'inline-link';
+ children?: ReactNode;
+ variant?: 'primary' | 'secondary' | 'trade' | 'accent' | 'inline-link';
className?: string;
prependIconName?: IconName;
appendIconName?: IconName;
+ boxShadow?: boolean;
}
export interface ButtonProps
extends ButtonHTMLAttributes,
@@ -25,21 +31,30 @@ export interface AnchorButtonProps
extends AnchorHTMLAttributes,
CommonProps {}
-const getClasses = (
- variant: CommonProps['variant'],
- paddingLeftProvided: boolean,
- paddingRightProvided: boolean,
- borderWidthProvided: boolean,
- heightProvided: boolean
+export const getButtonClasses = (
+ className?: string,
+ variant?: 'primary' | 'secondary' | 'trade' | 'accent' | 'inline-link',
+ boxShadow?: boolean
) => {
+ const paddingLeftProvided = includesLeftPadding(className);
+ const paddingRightProvided = includesRightPadding(className);
+ const borderWidthProvided = includesBorderWidth(className);
+ const heightProvided = includesHeight(className);
+
// Add classes into variables if there are multiple classes shared in multiple button styles
const sharedClasses =
- 'inline-flex items-center justify-center box-border transition-all disabled:no-underline';
- const underlineOnHover = 'no-underline hover:underline';
- const commonHoverAndActiveBorder =
- 'hover:border-black dark:hover:border-white active:border-black dark:active:border-white';
+ 'inline-flex items-center justify-center box-border transition-[background-color] ease-linear duration-50 disabled:no-underline';
+ const commonButtonClasses = classnames(
+ 'relative disabled:static',
+ 'text-ui font-semibold focus-visible:outline-none border no-underline hover:no-underline',
+ {
+ 'shadow-none': !boxShadow,
+ 'shadow-[3px_3px_0_0] focus-visible:shadow-vega-pink dark:focus-visible:shadow-vega-yellow active:top-[1px] active:left-[1px] active:shadow-[2px_2px_0_0]':
+ boxShadow === undefined || boxShadow,
+ }
+ );
const commonDisabled =
- 'disabled:bg-black-10 dark:disabled:bg-white-10 disabled:text-black-60 dark:disabled:text-white-60 disabled:border-black-25 dark:disabled:border-white-25';
+ 'disabled:bg-black-10 dark:disabled:bg-white-10 disabled:text-black-60 dark:disabled:text-white-60 disabled:border-black-25 dark:disabled:border-white-25 disabled:shadow-none dark:disabled:shadow-none';
const inlineTextColour =
'text-black-95 dark:text-white-95 hover:text-black hover:dark:text-white active:text-black dark:active:text-vega-yellow';
@@ -62,104 +77,92 @@ const getClasses = (
const primaryClasses = [
sharedClasses,
- commonHoverAndActiveBorder,
- underlineOnHover,
+ commonButtonClasses,
commonDisabled,
standardButtonPaddingLeft,
standardButtonPaddingRight,
standardButtonBorderWidth,
buttonHeight,
- 'bg-black dark:bg-white hover:bg-black-80 dark:hover:bg-white-80 active:bg-white dark:active:bg-black',
- 'text-ui text-white dark:text-black active:text-black dark:active:text-white',
+ 'bg-black dark:bg-white hover:bg-black-80 dark:hover:bg-white-90 active:bg-black-80 dark:active:bg-white-90',
+ 'border-white dark:border-black shadow-black active:shadow-black dark:shadow-white-80 dark:active:shadow-white',
+ 'text-white dark:text-black',
];
const secondaryClasses = [
sharedClasses,
- commonHoverAndActiveBorder,
- underlineOnHover,
+ commonButtonClasses,
commonDisabled,
standardButtonPaddingLeft,
standardButtonPaddingRight,
standardButtonBorderWidth,
buttonHeight,
- 'bg-white dark:bg-black hover:bg-black-25 dark:hover:bg-white-25 active:bg-black dark:active:bg-white',
- 'text-ui text-black dark:text-white active:text-white dark:active:text-black',
- 'border-black-60 dark:border-white-60 hover:border-black',
+ 'bg-white dark:bg-black hover:bg-black-25 dark:hover:bg-white-25',
+ 'border-black dark:border-white shadow-black dark:shadow-white',
+ 'text-black dark:text-white',
+ ];
+
+ const tradeClasses = [
+ sharedClasses,
+ commonButtonClasses,
+ commonDisabled,
+ standardButtonPaddingLeft,
+ standardButtonPaddingRight,
+ standardButtonBorderWidth,
+ buttonHeight,
+ 'bg-vega-green hover:bg-vega-green-medium',
+ 'border-black disabled:shadow-none dark:disabled:shadow-none shadow-black dark:shadow-white',
+ 'text-black',
];
const accentClasses = [
sharedClasses,
- commonHoverAndActiveBorder,
- underlineOnHover,
commonDisabled,
standardButtonPaddingLeft,
standardButtonPaddingRight,
standardButtonBorderWidth,
buttonHeight,
- 'bg-vega-yellow dark:bg-vega-yellow hover:bg-yellow/dark dark:hover:bg-vega-yellow/30 active:bg-white dark:active:bg-black',
- 'text-ui uppercase text-black dark:text-black hover:text-white dark:hover:text-white active:text-black dark:active:text-white',
+ 'bg-vega-yellow dark:bg-vega-yellow hover:bg-vega-yellow-dark dark:hover:bg-vega-yellow-dark active:bg-white dark:active:bg-black',
+ 'uppercase text-black dark:text-black hover:text-white dark:hover:text-white active:text-black dark:active:text-white',
'border-transparent dark:border-transparent',
];
- const inlineClasses = [
- sharedClasses,
- inlineButtonPaddingLeft,
- inlineButtonPaddingRight,
- buttonHeight,
- inlineTextColour,
- 'border-none',
- 'text-ui',
- ];
-
const inlineLinkClasses = [
sharedClasses,
inlineButtonPaddingLeft,
inlineButtonPaddingRight,
buttonHeight,
inlineTextColour,
- 'underline hover:underline',
+ 'underline hover:underline hover:text-black-60 dark:hover:text-white-80',
'border-none',
];
+ let variantClasses: string[];
+
switch (variant) {
case 'primary':
- return primaryClasses;
+ variantClasses = primaryClasses;
+ break;
case 'secondary':
- return secondaryClasses;
+ variantClasses = secondaryClasses;
+ break;
+ case 'trade':
+ variantClasses = tradeClasses;
+ break;
case 'accent':
- return accentClasses;
- case 'inline':
- return inlineClasses;
+ variantClasses = accentClasses;
+ break;
case 'inline-link':
- return inlineLinkClasses;
+ variantClasses = inlineLinkClasses;
+ break;
default:
- return '';
+ variantClasses = [''];
}
+
+ return classNames(...variantClasses, className);
};
-const classes = (
- className: CommonProps['className'],
- variant: CommonProps['variant']
-) => {
- const paddingLeftProvided = includesLeftPadding(className);
- const paddingRightProvided = includesRightPadding(className);
- const borderWidthProvided = includesBorderWidth(className);
- const heightProvided = includesHeight(className);
-
- return classNames(
- getClasses(
- variant,
- paddingLeftProvided,
- paddingRightProvided,
- borderWidthProvided,
- heightProvided
- ),
- className
- );
-};
-
-const getContent = (
- children: React.ReactNode,
+export const getButtonContent = (
+ children: ReactNode,
prependIconName?: IconName,
appendIconName?: IconName
) => {
@@ -190,6 +193,7 @@ export const Button = forwardRef(
className,
prependIconName,
appendIconName,
+ boxShadow,
...props
},
ref
@@ -197,11 +201,11 @@ export const Button = forwardRef(
return (
- {getContent(children, prependIconName, appendIconName)}
+ {getButtonContent(children, prependIconName, appendIconName)}
);
}
@@ -215,13 +219,18 @@ export const AnchorButton = forwardRef(
className,
prependIconName,
appendIconName,
+ boxShadow,
...props
},
ref
) => {
return (
-
- {getContent(children, prependIconName, appendIconName)}
+
+ {getButtonContent(children, prependIconName, appendIconName)}
);
}
diff --git a/libs/ui-toolkit/src/components/callout/callout.spec.tsx b/libs/ui-toolkit/src/components/callout/callout.spec.tsx
index 2ac6761c0..5210f76d3 100644
--- a/libs/ui-toolkit/src/components/callout/callout.spec.tsx
+++ b/libs/ui-toolkit/src/components/callout/callout.spec.tsx
@@ -17,31 +17,29 @@ it('renders title and icon', () => {
it(`Applies class for success intent`, () => {
render();
- expect(screen.getByTestId('callout')).toHaveClass('shadow-danger');
+ expect(screen.getByTestId('callout')).toHaveClass('border-danger');
});
it(`Applies class for warning intent`, () => {
render();
- expect(screen.getByTestId('callout')).toHaveClass('shadow-warning');
+ expect(screen.getByTestId('callout')).toHaveClass('border-warning');
});
it(`Applies class for danger intent`, () => {
render();
- expect(screen.getByTestId('callout')).toHaveClass('shadow-danger');
+ expect(screen.getByTestId('callout')).toHaveClass('border-danger');
});
it(`Applies class for primary intent`, () => {
render();
expect(screen.getByTestId('callout')).toHaveClass(
- 'shadow-vega-pink',
- 'dark:shadow-vega-yellow'
+ 'border-black dark:border-white'
);
});
it(`Applies class for none intent`, () => {
render();
expect(screen.getByTestId('callout')).toHaveClass(
- 'shadow-black',
- 'dark:shadow-white'
+ 'border-black dark:border-white'
);
});
diff --git a/libs/ui-toolkit/src/components/callout/callout.stories.tsx b/libs/ui-toolkit/src/components/callout/callout.stories.tsx
index aaace79dc..c7d437ee7 100644
--- a/libs/ui-toolkit/src/components/callout/callout.stories.tsx
+++ b/libs/ui-toolkit/src/components/callout/callout.stories.tsx
@@ -21,31 +21,31 @@ const Template: ComponentStory = (args) => (
export const Default = Template.bind({});
Default.args = {
- children: 'Content',
+ children: 'No intent supplied',
};
export const Primary = Template.bind({});
Primary.args = {
intent: Intent.Primary,
- children: 'Content',
+ children: 'Intent: Primary',
};
export const Danger = Template.bind({});
Danger.args = {
intent: Intent.Danger,
- children: 'Content',
+ children: 'Intent: Danger',
};
export const Warning = Template.bind({});
Warning.args = {
intent: Intent.Warning,
- children: 'Content',
+ children: 'Intent: Warning',
};
export const Success = Template.bind({});
Success.args = {
intent: Intent.Success,
- children: 'Content',
+ children: 'Intent: Success',
};
export const IconAndContent = Template.bind({});
@@ -55,7 +55,7 @@ IconAndContent.args = {
iconName: 'endorsed',
children: (
-
With a longer explaination
+
With a longer explanation
Action
@@ -74,7 +74,7 @@ CustomIconAndContent.args = {
),
children: (
-
With a longer explaination
+
With a longer explanation
Action
@@ -89,7 +89,7 @@ Loading.args = {
isLoading: true,
children: (
-
With a longer explaination
+
With a longer explanation
Action
diff --git a/libs/ui-toolkit/src/components/callout/callout.tsx b/libs/ui-toolkit/src/components/callout/callout.tsx
index a226cb941..999058872 100644
--- a/libs/ui-toolkit/src/components/callout/callout.tsx
+++ b/libs/ui-toolkit/src/components/callout/callout.tsx
@@ -1,13 +1,13 @@
-import type { ReactNode } from 'react';
+import type { ReactNode, ReactElement } from 'react';
import classNames from 'classnames';
-import { getIntentShadow, Intent } from '../../utils/intent';
+import { getIntentBorder, Intent } from '../../utils/intent';
import { Loader } from '../loader';
import type { IconName } from '../icon';
import { Icon } from '../icon';
interface CalloutRootProps {
- children?: React.ReactNode;
- title?: React.ReactElement | string;
+ children?: ReactNode;
+ title?: ReactElement | string;
intent?: Intent;
headingLevel?: 1 | 2 | 3 | 4 | 5 | 6;
isLoading?: boolean;
@@ -89,13 +89,10 @@ export function Callout({
const className = classNames(
'flex gap-20',
- 'border',
- 'border-black',
- 'dark:border-white',
'text-body-large',
'dark:text-white',
'p-16',
- getIntentShadow(intent)
+ getIntentBorder(intent)
);
const TitleTag: keyof JSX.IntrinsicElements = headingLevel
? `h${headingLevel}`
diff --git a/libs/ui-toolkit/src/components/checkbox/checkbox.spec.tsx b/libs/ui-toolkit/src/components/checkbox/checkbox.spec.tsx
new file mode 100644
index 000000000..49c7a5408
--- /dev/null
+++ b/libs/ui-toolkit/src/components/checkbox/checkbox.spec.tsx
@@ -0,0 +1,64 @@
+import { fireEvent, render, screen } from '@testing-library/react';
+import { Checkbox } from './checkbox';
+
+describe('Checkbox', () => {
+ it('should render checkbox with label successfully', () => {
+ render(
);
+ expect(screen.getByText('test')).toBeInTheDocument();
+ });
+
+ it('should render a checked checkbox if specified in state', () => {
+ render(
);
+ expect(screen.getByTestId('checkbox-checked')).toBeInTheDocument();
+ });
+
+ it('should render an unchecked checkbox if specified in state', () => {
+ render(
);
+ expect(screen.getByTestId('checkbox-unchecked')).toBeInTheDocument();
+ });
+
+ it('should render an indeterminate checkbox if specified in state', () => {
+ render(
);
+ expect(screen.getByTestId('checkbox-indeterminate')).toBeInTheDocument();
+ });
+
+ it('should render a checkbox in error if specified', () => {
+ render(
);
+ expect(screen.getByTestId('checkbox-error')).toBeInTheDocument();
+ });
+
+ it('should render a checked checkbox in error if specified', () => {
+ render(
);
+ expect(screen.getByTestId('checkbox-error-checked')).toBeInTheDocument();
+ });
+
+ it('should render an unchecked checkbox in error if specified', () => {
+ render(
+
+ );
+ expect(screen.getByTestId('checkbox-error-unchecked')).toBeInTheDocument();
+ });
+
+ it('should render an indeterminate checkbox in error if specified', () => {
+ render(
+
+ );
+ expect(
+ screen.getByTestId('checkbox-error-indeterminate')
+ ).toBeInTheDocument();
+ });
+
+ it('fires callback on change if provided', () => {
+ const callback = jest.fn();
+
+ render(
);
+
+ const checkbox = screen.getByText('onchange');
+ fireEvent.click(checkbox);
+ expect(callback.mock.calls.length).toEqual(1);
+ });
+});
diff --git a/libs/ui-toolkit/src/components/checkbox/checkbox.stories.tsx b/libs/ui-toolkit/src/components/checkbox/checkbox.stories.tsx
new file mode 100644
index 000000000..e5dca2d87
--- /dev/null
+++ b/libs/ui-toolkit/src/components/checkbox/checkbox.stories.tsx
@@ -0,0 +1,45 @@
+import type { ComponentStory, ComponentMeta } from '@storybook/react';
+import { Checkbox } from './checkbox';
+import { useState } from 'react';
+
+export default {
+ component: Checkbox,
+ title: 'Checkbox',
+} as ComponentMeta
;
+
+export const Controlled: ComponentStory = () => {
+ const [checkboxState, setCheckboxState] = useState<
+ 'checked' | 'unchecked' | 'indeterminate'
+ >('indeterminate');
+
+ return (
+ {
+ if (
+ checkboxState === 'indeterminate' ||
+ checkboxState === 'unchecked'
+ ) {
+ setCheckboxState('checked');
+ }
+
+ if (checkboxState === 'checked') {
+ setCheckboxState('unchecked');
+ }
+ }}
+ />
+ );
+};
+
+export const Default: ComponentStory = () => (
+
+);
+
+export const Error: ComponentStory = () => (
+
+);
+
+export const Disabled: ComponentStory = () => (
+
+);
diff --git a/libs/ui-toolkit/src/components/checkbox/checkbox.tsx b/libs/ui-toolkit/src/components/checkbox/checkbox.tsx
new file mode 100644
index 000000000..e9928f221
--- /dev/null
+++ b/libs/ui-toolkit/src/components/checkbox/checkbox.tsx
@@ -0,0 +1,81 @@
+import classnames from 'classnames';
+import { Icon } from '../icon';
+import type { ChangeEvent, InputHTMLAttributes } from 'react';
+
+export interface CheckboxProps extends InputHTMLAttributes {
+ label: string;
+ className?: string;
+ state?: 'checked' | 'unchecked' | 'indeterminate';
+ error?: boolean;
+ onChange?: (e: ChangeEvent) => void;
+}
+
+export const Checkbox = ({
+ label,
+ className,
+ state,
+ error,
+ onChange,
+ ...props
+}: CheckboxProps) => {
+ const containerClasses = classnames(
+ className,
+ 'grid grid-cols-[auto_1fr] select-none'
+ );
+ const inputClasses = 'sr-only peer';
+ const vegaCheckboxClasses = classnames(
+ 'col-start-1 row-start-1',
+ 'inline-block w-20 h-20 relative z-0',
+ 'shadow-input dark:shadow-input-dark bg-white dark:bg-white-25',
+ 'focus-visible:outline-none focus-visible:shadow-checkbox-focus dark:focus-visible:shadow-checkbox-focus-dark',
+ 'cursor-pointer peer-disabled:cursor-default',
+ {
+ 'input-border dark:input-border-dark': !error,
+ 'border border-vega-red': error,
+ }
+ );
+ // In uncontrolled elements without state, we apply the hidden class and 'peer-checked' can
+ // override it as necessary. At other times, we control display properties via state conditions.
+ const iconClasses = classnames(
+ 'col-start-1 row-start-1 place-self-center relative z-50 pointer-events-none',
+ {
+ hidden: !state || state === 'unchecked',
+ }
+ );
+ const tickClasses = classnames(iconClasses, {
+ 'peer-checked:block': !state,
+ block: state === 'checked',
+ hidden: state === 'indeterminate',
+ });
+ const minusClasses = classnames(iconClasses, {
+ block: state === 'indeterminate',
+ hidden: state === 'checked',
+ });
+ const labelClasses = classnames(
+ 'col-start-2 row-start-1 pl-8 cursor-pointer peer-disabled:cursor-default'
+ );
+
+ return (
+
+ );
+};
diff --git a/libs/ui-toolkit/src/components/checkbox/index.ts b/libs/ui-toolkit/src/components/checkbox/index.ts
new file mode 100644
index 000000000..8d78b3e23
--- /dev/null
+++ b/libs/ui-toolkit/src/components/checkbox/index.ts
@@ -0,0 +1 @@
+export * from './checkbox';
diff --git a/libs/ui-toolkit/src/components/dialog/dialog.stories.tsx b/libs/ui-toolkit/src/components/dialog/dialog.stories.tsx
index 968e276ba..f06014142 100644
--- a/libs/ui-toolkit/src/components/dialog/dialog.stories.tsx
+++ b/libs/ui-toolkit/src/components/dialog/dialog.stories.tsx
@@ -15,7 +15,9 @@ const Template: ComponentStory = (args) => {
return (
setOpen(true)}>Open dialog
-
+
);
};
@@ -23,38 +25,38 @@ const Template: ComponentStory = (args) => {
export const Default = Template.bind({});
Default.args = {
open: false,
- title: 'Title',
+ title: 'No intent supplied',
children: Some content
,
};
+export const Primary = Template.bind({});
+Primary.args = {
+ open: false,
+ title: 'Intent: Primary',
+ children: Some content
,
+ intent: Intent.Primary,
+};
+
export const Danger = Template.bind({});
Danger.args = {
open: false,
- title: 'Danger',
+ title: 'Intent: Danger',
children: Some content
,
intent: Intent.Danger,
};
-export const Success = Template.bind({});
-Success.args = {
- open: false,
- title: 'Success',
- children: Some content
,
- intent: Intent.Success,
-};
-
export const Warning = Template.bind({});
Warning.args = {
open: false,
- title: 'Warning',
+ title: 'Intent: Warning',
children: Some content
,
intent: Intent.Warning,
};
-export const Modal = Template.bind({});
-Modal.args = {
+export const Success = Template.bind({});
+Success.args = {
open: false,
- title: 'Modal (Prompt)',
+ title: 'Intent: Success',
children: Some content
,
- intent: Intent.Warning,
+ intent: Intent.Success,
};
diff --git a/libs/ui-toolkit/src/components/dialog/dialog.tsx b/libs/ui-toolkit/src/components/dialog/dialog.tsx
index e7c7309ca..e6bf068b7 100644
--- a/libs/ui-toolkit/src/components/dialog/dialog.tsx
+++ b/libs/ui-toolkit/src/components/dialog/dialog.tsx
@@ -2,7 +2,7 @@ import * as DialogPrimitives from '@radix-ui/react-dialog';
import classNames from 'classnames';
import type { ReactNode } from 'react';
import type { Intent } from '../../utils/intent';
-import { getIntentShadow } from '../../utils/intent';
+import { getIntentShadow, getIntentBorder } from '../../utils/intent';
import { Icon } from '../icon';
interface DialogProps {
@@ -30,6 +30,7 @@ export function Dialog({
// Need to apply background and text colors again as content is rendered in a portal
'dark:bg-black dark:text-white-95 bg-white text-black-95',
getIntentShadow(intent),
+ getIntentBorder(intent),
contentClassNames
);
return (
@@ -41,10 +42,13 @@ export function Dialog({
/>
-
+
{title && (
{
return (
-
- Options
+
+ Select many things
-
+
{checkboxItems.map(({ label, state: [checked, setChecked] }) => (
-
-
-
{label}
))}
@@ -56,13 +50,13 @@ export const CheckboxItems = () => {
export const RadioItems = () => {
const files = ['README.md', 'index.js', 'page.css'];
- const [file, setFile] = useState(files[1]);
+ const [selected, setSelected] = useState(files[1]);
return (
- Open
+ Open
console.log('minimize')}>
@@ -75,19 +69,38 @@ export const RadioItems = () => {
Smaller
-
+
{files.map((file) => (
{file}
-
-
-
))}
-
Selected file: {file}
+
Selected file: {selected}
+
+ );
+};
+
+export const IconMenu = () => {
+ const iconMenuItems = [
+ { label: 'IconMenu Item 1' },
+ { label: 'IconMenu Item 2' },
+ ];
+
+ return (
+
+
+
+
+
+
+ {iconMenuItems.map(({ label }) => (
+ {label}
+ ))}
+
+
);
};
diff --git a/libs/ui-toolkit/src/components/dropdown-menu/dropdown-menu.tsx b/libs/ui-toolkit/src/components/dropdown-menu/dropdown-menu.tsx
index 7073e7e77..7eaaf2529 100644
--- a/libs/ui-toolkit/src/components/dropdown-menu/dropdown-menu.tsx
+++ b/libs/ui-toolkit/src/components/dropdown-menu/dropdown-menu.tsx
@@ -1,34 +1,31 @@
import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';
import classNames from 'classnames';
import { forwardRef } from 'react';
+import { Button } from '../button';
-const itemStyles = classNames([
- 'text-ui',
- 'text-black',
- 'dark:text-white',
- 'flex',
- 'items-center',
- 'justify-between',
- 'leading-1',
+const itemClass = classNames(
+ 'relative',
+ 'flex items-center justify-between',
+ 'text-ui leading-1',
+ 'h-[25px]',
+ 'py-0 pr-8',
'cursor-default',
+ 'hover:cursor-pointer',
'select-none',
'whitespace-nowrap',
- 'h-[25px]',
- 'py-0',
- 'pr-8',
- 'color-black',
-]);
+ 'focus:bg-vega-pink dark:focus:bg-vega-yellow',
+ 'focus:text-white dark:focus:text-black',
+ 'focus:outline-none'
+);
-const itemClass = classNames(itemStyles, [
- 'focus:bg-vega-yellow',
- 'dark:focus:bg-vega-yellow',
- 'focus:text-black',
- 'dark:focus:text-black',
- 'focus:outline-none',
-]);
-
-function getItemClasses(inset: boolean) {
- return classNames(itemClass, inset ? 'pl-28' : 'pl-4', 'relative');
+function getItemClasses(inset: boolean, checked?: boolean) {
+ return classNames(
+ itemClass,
+ inset ? 'pl-28' : 'pl-8',
+ checked
+ ? 'bg-vega-pink dark:bg-vega-yellow text-white dark:text-black'
+ : 'text-black dark:text-white'
+ );
}
/**
@@ -40,7 +37,25 @@ export const DropdownMenu = DropdownMenuPrimitive.Root;
* The button that toggles the dropdown menu.
* By default, the {@link DropdownMenuContent} will position itself against the trigger.
*/
-export const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
+export const DropdownMenuTrigger = forwardRef<
+ React.ElementRef,
+ React.ComponentProps
+>(({ children, className }, forwardedRef) => (
+
+
+ {children}
+
+
+));
/**
* Used to group multiple {@link DropdownMenuRadioItem}s.
@@ -58,7 +73,7 @@ export const DropdownMenuContent = forwardRef<
{...contentProps}
ref={forwardedRef}
className={classNames(
- 'inline-block box-border border-1 border-black bg-white dark:bg-black p-4',
+ 'inline-block box-border border-1 border-black bg-white dark:bg-black-60',
className
)}
/>
@@ -92,7 +107,12 @@ export const DropdownMenuCheckboxItem = forwardRef<
));
diff --git a/libs/ui-toolkit/src/components/form-group/form-group.tsx b/libs/ui-toolkit/src/components/form-group/form-group.tsx
index 5dcbed6c2..ce3575844 100644
--- a/libs/ui-toolkit/src/components/form-group/form-group.tsx
+++ b/libs/ui-toolkit/src/components/form-group/form-group.tsx
@@ -1,32 +1,49 @@
import classNames from 'classnames';
import type { ReactNode } from 'react';
+import classnames from 'classnames';
interface FormGroupProps {
children: ReactNode;
label?: string;
labelFor?: string;
labelAlign?: 'left' | 'right';
+ labelDescription?: string;
className?: string;
+ hasError?: boolean;
}
export const FormGroup = ({
children,
label,
labelFor,
+ labelDescription,
labelAlign = 'left',
className,
+ hasError,
}: FormGroupProps) => {
- const labelClasses = classNames('block text-ui mb-4', {
- 'text-right': labelAlign === 'right',
- });
return (
{label && (
-