Skip to content

Commit 697137b

Browse files
authored
Merge pull request #59 from input-output-hk/feat/lw-9231-add-simple-asset-input
feat: add simple version of asset input [LW-9231]
2 parents 674f6a6 + f3ca7f1 commit 697137b

13 files changed

+156
-29
lines changed

src/design-system/asset-input/amount-input.component.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,25 @@ import React from 'react';
33
import { Box } from '../box';
44

55
import * as cx from './amount-input.css';
6+
import { AmountInputAlignments } from './types';
67

78
interface Props {
9+
alignment?: AmountInputAlignments;
810
onChange?: (value: string) => void;
911
value?: string;
1012
id: string;
1113
}
1214

1315
export const AmountInput = ({
16+
alignment = 'right',
1417
onChange,
1518
value,
1619
id,
1720
}: Readonly<Props>): JSX.Element => {
1821
return (
1922
<Box className={cx.amountInputSizer} data-value={value}>
2023
<input
21-
className={cx.amountInput}
24+
className={cx.amountInput[alignment]}
2225
value={value}
2326
size={1}
2427
onChange={({ target }): void => onChange?.(target.value)}

src/design-system/asset-input/amount-input.css.ts

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { styleVariants } from '@vanilla-extract/css';
2+
13
import { style, vars } from '../../design-tokens';
24
import { bold } from '../text/text.css';
35

@@ -20,12 +22,11 @@ export const amountInputSizer = style([
2022
},
2123
]);
2224

23-
export const amountInput = style([
25+
const amountInputBase = style([
2426
inputTypography,
2527
bold,
2628
{
2729
gridArea: '1 / 2',
28-
textAlign: 'right',
2930
border: 'none',
3031
width: 'auto',
3132
background: 'none',
@@ -39,3 +40,18 @@ export const amountInput = style([
3940
},
4041
},
4142
]);
43+
44+
export const amountInput = styleVariants({
45+
left: [
46+
amountInputBase,
47+
{
48+
textAlign: 'left',
49+
},
50+
],
51+
right: [
52+
amountInputBase,
53+
{
54+
textAlign: 'right',
55+
},
56+
],
57+
});

src/design-system/asset-input/asset-input.component.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,13 @@ import * as cx from './asset-input.css';
99
import { MaxButton } from './max-button.component';
1010
import { TickerButton } from './ticker-button.component';
1111

12-
import type { Asset, AssetState } from './asset-input.data';
12+
import type { AssetWithFiat, AssetState } from './asset-input.data';
1313

1414
interface Props {
1515
state: AssetState;
16-
onTickerClick?: (asset: Readonly<Asset>) => void;
17-
onAmountChange?: (asset: Readonly<Asset>, amount: string) => void;
18-
onMaxClick?: (asset: Readonly<Asset>) => void;
16+
onTickerClick?: (asset: Readonly<AssetWithFiat>) => void;
17+
onAmountChange?: (asset: Readonly<AssetWithFiat>, amount: string) => void;
18+
onMaxClick?: (asset: Readonly<AssetWithFiat>) => void;
1919
}
2020

2121
export const AssetInput = ({

src/design-system/asset-input/asset-input.data.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,18 @@ export interface Asset {
33
ticker: string;
44
balance: string;
55
amount: string;
6+
}
7+
8+
export interface AssetWithFiat extends Asset {
69
fiat: {
710
value: string;
811
ticker: string;
912
};
1013
}
1114

12-
export type AssetState =
15+
export type AssetState<A extends Asset = AssetWithFiat> =
1316
| {
1417
type: 'valid';
15-
asset: Asset;
18+
asset: A;
1619
}
17-
| { type: 'invalid'; asset: Asset; error: string };
20+
| { type: 'invalid'; asset: A; error: string };

src/design-system/asset-input/asset-input.fixtures.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import type { Asset, AssetState } from './asset-input.data';
1+
import type { AssetWithFiat, AssetState } from './asset-input.data';
22

3-
export const asset: Asset = {
3+
export const asset: AssetWithFiat = {
44
balance: String(10_000_000),
55
amount: '',
66
id: '',

src/design-system/asset-input/asset-input.stories.tsx

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,14 @@ import {
1313
ColorSchemaTable,
1414
} from '../decorators';
1515
import { Divider } from '../divider';
16-
import { Grid } from '../grid';
17-
import { Cell } from '../grid/cell.component';
16+
import { Cell, Grid } from '../grid';
1817

1918
import { AssetInput } from './asset-input.component';
2019
import { invalidState, validState } from './asset-input.fixtures';
2120
import { MaxButton } from './max-button.component';
21+
import { SimpleAssetInput } from './simple-asset-input.component';
2222

23-
import type { Asset, AssetState } from './asset-input.data';
23+
import type { AssetWithFiat, AssetState } from './asset-input.data';
2424

2525
const subtitle = ``;
2626

@@ -61,7 +61,12 @@ export const Overview = (): JSX.Element => (
6161
<Cell>
6262
<Section title="Overview">
6363
<Variants.Table
64-
headers={['Browser view — simple', 'Browser view — simple + error']}
64+
headers={[
65+
'Complex — valid',
66+
'Complex — invalid',
67+
'Simple - valid',
68+
'Simple - invalid',
69+
]}
6570
>
6671
<Variants.Row>
6772
<Variants.Cell>
@@ -70,6 +75,18 @@ export const Overview = (): JSX.Element => (
7075
<Variants.Cell>
7176
<AssetInput state={invalidState('1')} />
7277
</Variants.Cell>
78+
<Variants.Cell>
79+
<SimpleAssetInput
80+
state={validState('1')}
81+
balanceLabel="Balance Available"
82+
/>
83+
</Variants.Cell>
84+
<Variants.Cell>
85+
<SimpleAssetInput
86+
state={invalidState('1')}
87+
balanceLabel="Balance Available"
88+
/>
89+
</Variants.Cell>
7390
</Variants.Row>
7491
</Variants.Table>
7592
</Section>
@@ -105,14 +122,17 @@ type Interactions = ComponentStory<typeof AssetInput>;
105122
export const Interactions: Interactions = (): JSX.Element => {
106123
const [state, setState] = useState<AssetState>(validState('1'));
107124

108-
const onTickerClick = (asset: Readonly<Asset>): void => {
125+
const onTickerClick = (asset: Readonly<AssetWithFiat>): void => {
109126
setState(currentState => ({
110127
...currentState,
111128
asset: { ...currentState.asset, ticker: `Token ${asset.id}` },
112129
}));
113130
};
114131

115-
const onAmountChange = (asset: Readonly<Asset>, amount: string): void => {
132+
const onAmountChange = (
133+
asset: Readonly<AssetWithFiat>,
134+
amount: string,
135+
): void => {
116136
setState(currentState => {
117137
if (currentState.asset.id !== asset.id) {
118138
return currentState;
@@ -141,7 +161,7 @@ export const Interactions: Interactions = (): JSX.Element => {
141161
});
142162
};
143163

144-
const onMaxClick = (asset: Readonly<Asset>): void => {
164+
const onMaxClick = (asset: Readonly<AssetWithFiat>): void => {
145165
setState(currentState => {
146166
return {
147167
...currentState,
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
export { AssetInput } from './asset-input.component';
2+
export { SimpleAssetInput } from './simple-asset-input.component';
23
export * as Data from './asset-input.data';
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import React from 'react';
2+
3+
import { Box } from '../box';
4+
import { Text } from '../text';
5+
6+
import { AmountInput } from './amount-input.component';
7+
import * as cx from './simple-asset-input.css';
8+
9+
import type { Asset, AssetState } from './asset-input.data';
10+
11+
interface Props {
12+
state: AssetState<Asset>;
13+
balanceLabel: string;
14+
onAmountChange?: (asset: Readonly<Asset>, amount: string) => void;
15+
}
16+
17+
export const SimpleAssetInput = ({
18+
state,
19+
balanceLabel,
20+
onAmountChange,
21+
}: Readonly<Props>): JSX.Element => (
22+
<div className={cx.root}>
23+
<Box className={cx.amountBox}>
24+
<AmountInput
25+
id={state.asset.id}
26+
value={state.asset.amount}
27+
alignment="left"
28+
onChange={(value): void => {
29+
onAmountChange?.(state.asset, value);
30+
}}
31+
/>
32+
</Box>
33+
<Box className={cx.balance}>
34+
<Text.Body.Normal color="secondary">
35+
{balanceLabel}: {state.asset.balance} {state.asset.ticker}
36+
</Text.Body.Normal>
37+
</Box>
38+
{state.type === 'invalid' && (
39+
<Box className={cx.error}>
40+
<Text.Label
41+
color="error"
42+
data-testid={`asset-input-error-${state.asset.id}`}
43+
>
44+
{state.error}
45+
</Text.Label>
46+
</Box>
47+
)}
48+
</div>
49+
);
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { sx, style, vars } from '../../design-tokens';
2+
3+
export const root = style([
4+
sx({
5+
width: '$fill',
6+
rowGap: '$10',
7+
}),
8+
{
9+
background: vars.colors.$input_container_bgColor,
10+
borderRadius: vars.radius.$medium,
11+
padding: `${vars.spacing.$16} ${vars.spacing.$20}`,
12+
display: 'grid',
13+
gridTemplateAreas: `
14+
"amount amount"
15+
"balance balance"
16+
"error ."
17+
`,
18+
},
19+
]);
20+
21+
export const amountBox = style({ gridArea: 'amount' });
22+
23+
export const balance = style({ gridArea: 'balance' });
24+
25+
export const error = style({ gridArea: 'error' });
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export type AmountInputAlignments = 'left' | 'right';

src/design-system/bundle-input/bundle-input.component.tsx

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,13 @@ import type { Data } from '../asset-input';
1616
export type Props = PropsWithChildren<{
1717
state?: Data.AssetState[];
1818
onAddAsset?: () => void;
19-
onRemoveAsset?: (asset: Readonly<Data.Asset>) => void;
20-
onAmountChange?: (asset: Readonly<Data.Asset>, amount: string) => void;
21-
onTickerClick?: (asset: Readonly<Data.Asset>) => void;
22-
onMaxClick?: (asset: Readonly<Data.Asset>) => void;
19+
onRemoveAsset?: (asset: Readonly<Data.AssetWithFiat>) => void;
20+
onAmountChange?: (
21+
asset: Readonly<Data.AssetWithFiat>,
22+
amount: string,
23+
) => void;
24+
onTickerClick?: (asset: Readonly<Data.AssetWithFiat>) => void;
25+
onMaxClick?: (asset: Readonly<Data.AssetWithFiat>) => void;
2326
}>;
2427

2528
export const BundleInput = ({

src/design-system/bundle-input/bundle-input.stories.tsx

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,10 @@ import { Cell } from '../grid/cell.component';
2020
import { BundleInput } from './bundle-input.component';
2121
import { RemoveButton } from './remove-button.component';
2222

23-
import type { Asset, AssetState } from '../asset-input/asset-input.data';
23+
import type {
24+
AssetWithFiat,
25+
AssetState,
26+
} from '../asset-input/asset-input.data';
2427

2528
const subtitle = ``;
2629

@@ -132,7 +135,7 @@ export const Interactions: Interactions = (): JSX.Element => {
132135
setState([...state, validState((state.length + 1).toString())]);
133136
};
134137

135-
const onTickerClick = (asset: Readonly<Asset>): void => {
138+
const onTickerClick = (asset: Readonly<AssetWithFiat>): void => {
136139
setState(
137140
state.map(currentState => {
138141
if (currentState.asset.id === asset.id) {
@@ -147,7 +150,10 @@ export const Interactions: Interactions = (): JSX.Element => {
147150
);
148151
};
149152

150-
const onAmountChange = (asset: Readonly<Asset>, amount: string): void => {
153+
const onAmountChange = (
154+
asset: Readonly<AssetWithFiat>,
155+
amount: string,
156+
): void => {
151157
setState(
152158
state.map(currentState => {
153159
if (currentState.asset.id !== asset.id) {
@@ -178,7 +184,7 @@ export const Interactions: Interactions = (): JSX.Element => {
178184
);
179185
};
180186

181-
const onMaxClick = (asset: Readonly<Asset>): void => {
187+
const onMaxClick = (asset: Readonly<AssetWithFiat>): void => {
182188
setState(
183189
state.map(currentState => {
184190
if (currentState.asset.id !== asset.id) {
@@ -197,7 +203,7 @@ export const Interactions: Interactions = (): JSX.Element => {
197203
);
198204
};
199205

200-
const onRemoveAsset = (asset: Readonly<Asset>): void => {
206+
const onRemoveAsset = (asset: Readonly<AssetWithFiat>): void => {
201207
setState(state.filter(currentState => currentState.asset.id !== asset.id));
202208
};
203209

src/design-system/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ export { Divider } from './divider';
66
export { Flex } from './flex';
77
export { Grid, Cell } from './grid';
88
export { Text } from './text';
9-
export { AssetInput } from './asset-input';
9+
export { AssetInput, SimpleAssetInput } from './asset-input';
1010
export { BundleInput } from './bundle-input';
1111
export * as SubNavigation from './sub-navigation';
1212
export * as NavigationButton from './navigation-buttons';

0 commit comments

Comments
 (0)