-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Create more components in preparation for the v2 assets/transactions …
…pages (#1634) * Add table title functionality * Start building v2 pages * Build out Identicon properly * Start building out assets table * Add truncate to Text * Add iconOnly='adornment' to Button * Create the new CopyToClipboardButton * Create Shrink0 util component * Create AddressViewComponent * Create initial SegmentedControl * Convert to using Radix's RadioGroup * Add docblock * Update hover overlay * Fix border * Rename 'reset' to 'buttonBase'; add a cursor * Use buttonBase elsewhere as well * Add type to props * Update AddressViewComponent tests * Delete code that will be part of another PR * Add tests * Delete SegmentedControl for now * Return null * Create SegmentedControl component (#1635) * Create SegmentedControl component * Add density tag
- Loading branch information
1 parent
82383bf
commit 33f70a1
Showing
29 changed files
with
807 additions
and
73 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import { Address } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/keys/v1/keys_pb.js'; | ||
import { bech32mAddress } from '@penumbra-zone/bech32m/penumbra'; | ||
import { Identicon } from '../Identicon'; | ||
|
||
export interface AddressIconProps { | ||
address: Address; | ||
size: number; | ||
} | ||
|
||
/** | ||
* A simple component to display a consistently styled icon for a given address. | ||
*/ | ||
export const AddressIcon = ({ address, size }: AddressIconProps) => ( | ||
<Identicon uniqueIdentifier={bech32mAddress(address)} size={size} type='gradient' /> | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
import type { Meta, StoryObj } from '@storybook/react'; | ||
|
||
import { AddressViewComponent } from '.'; | ||
import { AddressView } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/keys/v1/keys_pb.js'; | ||
import { addressFromBech32m } from '@penumbra-zone/bech32m/penumbra'; | ||
import styled from 'styled-components'; | ||
|
||
const EXAMPLE_VIEW_DECODED = new AddressView({ | ||
addressView: { | ||
case: 'decoded', | ||
|
||
value: { | ||
address: { inner: new Uint8Array(80) }, | ||
index: { | ||
account: 0, | ||
randomizer: new Uint8Array([0, 0, 0]), | ||
}, | ||
}, | ||
}, | ||
}); | ||
|
||
const EXAMPLE_VIEW_OPAQUE = new AddressView({ | ||
addressView: { | ||
case: 'opaque', | ||
value: { | ||
address: addressFromBech32m( | ||
'penumbra1e8k5cyds484dxvapeamwveh5khqv4jsvyvaf5wwxaaccgfghm229qw03pcar3ryy8smptevstycch0qk3uu0rgkvtjpxy3cu3rjd0agawqtlz6erev28a6sg69u7cxy0t02nd4', | ||
), | ||
}, | ||
}, | ||
}); | ||
|
||
const MaxWidthWrapper = styled.div` | ||
width: 100%; | ||
overflow: hidden; | ||
`; | ||
|
||
const meta: Meta<typeof AddressViewComponent> = { | ||
component: AddressViewComponent, | ||
tags: ['autodocs', '!dev'], | ||
argTypes: { | ||
addressView: { | ||
options: ['Sample decoded address view', 'Sample opaque address view'], | ||
mapping: { | ||
'Sample decoded address view': EXAMPLE_VIEW_DECODED, | ||
'Sample opaque address view': EXAMPLE_VIEW_OPAQUE, | ||
}, | ||
}, | ||
}, | ||
decorators: [ | ||
Story => ( | ||
<MaxWidthWrapper> | ||
<Story /> | ||
</MaxWidthWrapper> | ||
), | ||
], | ||
}; | ||
export default meta; | ||
|
||
type Story = StoryObj<typeof AddressViewComponent>; | ||
|
||
export const Basic: Story = { | ||
args: { | ||
addressView: EXAMPLE_VIEW_DECODED, | ||
copyable: true, | ||
}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
import { | ||
Address, | ||
AddressIndex, | ||
AddressView, | ||
AddressView_Decoded, | ||
} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/keys/v1/keys_pb.js'; | ||
import { AddressViewComponent } from '.'; | ||
import { describe, expect, it } from 'vitest'; | ||
import { render } from '@testing-library/react'; | ||
import { PenumbraUIProvider } from '../PenumbraUIProvider'; | ||
|
||
const addressViewWithOneTimeAddress = new AddressView({ | ||
addressView: { | ||
case: 'decoded', | ||
|
||
value: new AddressView_Decoded({ | ||
address: new Address({ inner: new Uint8Array(80) }), | ||
index: new AddressIndex({ | ||
account: 0, | ||
// A one-time address is defined by a randomizer with at least one | ||
// non-zero byte. | ||
randomizer: new Uint8Array([1, 2, 3]), | ||
}), | ||
}), | ||
}, | ||
}); | ||
|
||
const addressViewWithNormalAddress = new AddressView({ | ||
addressView: { | ||
case: 'decoded', | ||
|
||
value: new AddressView_Decoded({ | ||
address: new Address({ inner: new Uint8Array(80) }), | ||
index: new AddressIndex({ | ||
account: 0, | ||
randomizer: new Uint8Array([0, 0, 0]), | ||
}), | ||
}), | ||
}, | ||
}); | ||
|
||
describe('<AddressViewComponent />', () => { | ||
describe('when `copyable` is `true`', () => { | ||
it('does not show the copy icon when the address is a one-time address', () => { | ||
const { queryByLabelText } = render( | ||
<AddressViewComponent addressView={addressViewWithOneTimeAddress} copyable />, | ||
{ wrapper: PenumbraUIProvider }, | ||
); | ||
|
||
expect(queryByLabelText('Copy')).toBeNull(); | ||
}); | ||
|
||
it('shows the copy icon when the address is not a one-time address', () => { | ||
const { queryByLabelText } = render( | ||
<AddressViewComponent addressView={addressViewWithNormalAddress} copyable />, | ||
{ wrapper: PenumbraUIProvider }, | ||
); | ||
|
||
expect(queryByLabelText('Copy')).not.toBeNull(); | ||
}); | ||
}); | ||
|
||
describe('when `copyable` is `false`', () => { | ||
it('does not show the copy icon when the address is a one-time address', () => { | ||
const { queryByLabelText } = render( | ||
<AddressViewComponent addressView={addressViewWithOneTimeAddress} copyable={false} />, | ||
{ wrapper: PenumbraUIProvider }, | ||
); | ||
|
||
expect(queryByLabelText('Copy')).toBeNull(); | ||
}); | ||
|
||
it('does not show the copy icon when the address is not a one-time address', () => { | ||
const { queryByLabelText } = render( | ||
<AddressViewComponent addressView={addressViewWithNormalAddress} copyable={false} />, | ||
{ wrapper: PenumbraUIProvider }, | ||
); | ||
|
||
expect(queryByLabelText('Copy')).toBeNull(); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
import { AddressIcon } from './AddressIcon'; | ||
import { AddressView } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/keys/v1/keys_pb.js'; | ||
import { bech32mAddress } from '@penumbra-zone/bech32m/penumbra'; | ||
import styled from 'styled-components'; | ||
import { Text } from '../Text'; | ||
import { CopyToClipboardButton } from '../CopyToClipboardButton'; | ||
import { Shrink0 } from '../utils/Shrink0'; | ||
|
||
const Root = styled.div` | ||
display: flex; | ||
gap: ${props => props.theme.spacing(2)}; | ||
align-items: center; | ||
`; | ||
|
||
export interface AddressViewProps { | ||
addressView: AddressView | undefined; | ||
copyable?: boolean; | ||
} | ||
|
||
// Renders an address or an address view. | ||
// If the view is given and is "visible", the account information will be displayed instead. | ||
export const AddressViewComponent = ({ addressView, copyable = true }: AddressViewProps) => { | ||
if (!addressView?.addressView.value?.address) { | ||
return null; | ||
} | ||
|
||
const accountIndex = | ||
addressView.addressView.case === 'decoded' | ||
? addressView.addressView.value.index?.account | ||
: undefined; | ||
const isOneTimeAddress = | ||
addressView.addressView.case === 'decoded' | ||
? !addressView.addressView.value.index?.randomizer.every(v => v === 0) // Randomized (and thus, a one-time address) if the randomizer is not all zeros. | ||
: undefined; | ||
|
||
const addressIndexLabel = isOneTimeAddress ? 'IBC Deposit Address for Account #' : 'Account #'; | ||
|
||
copyable = isOneTimeAddress ? false : copyable; | ||
|
||
const encodedAddress = bech32mAddress(addressView.addressView.value.address); | ||
|
||
return ( | ||
<Root> | ||
<Shrink0> | ||
<AddressIcon address={addressView.addressView.value.address} size={24} /> | ||
</Shrink0> | ||
|
||
{accountIndex === undefined ? ( | ||
<Text technical truncate> | ||
{encodedAddress} | ||
</Text> | ||
) : ( | ||
<Text strong truncate> | ||
{addressIndexLabel} | ||
{accountIndex} | ||
</Text> | ||
)} | ||
|
||
{copyable && ( | ||
<Shrink0> | ||
<CopyToClipboardButton text={encodedAddress} /> | ||
</Shrink0> | ||
)} | ||
</Root> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.