Skip to content

Commit

Permalink
merge branch main
Browse files Browse the repository at this point in the history
  • Loading branch information
alvaroraminelli committed Feb 8, 2024
2 parents 0f1794f + 146c645 commit aaf4eb5
Show file tree
Hide file tree
Showing 18 changed files with 727 additions and 69 deletions.
49 changes: 32 additions & 17 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,34 +1,49 @@
# Changelog

## 0.5.2

### Patch Changes

- cefcfa8: - **fix**: `<FrameMetadata>` component when used with Helmet. To ensure smooth functionality when used with Helmet as a wrapper component, it is crucial to flatten the Buttons loop. By @zizzamia #99
- **feat**: added `Avatar` component, to our Identity Kit. The `Avatar` component primarily focuses on showcasing ENS avatar for given Ethereum addresses, and defaults to a default SVG avatar when an ENS avatar isn't available. By @alvaroraminelli #69

## 0.5.1

### Patch Changes

- **feat**: added option for mint action on a Frame. By @zizzamia #93 f9f7652
- **feat**: added option for simple static links when creating a Frame. By @zizzamia #93
- **feat**: added `wrapper` prop to `<FrameMetadata />` component, that defaults to `React.Fragment` when not passed (original behavior). By @syntag #90 #91
- **feat**: exported `FrameMetadataResponse` type which can be useful when using `getFrameMetadata` in a TS project. By @syntag #90

## 0.5.0

### Minor Changes

- dc6f33d: - **fix**: ensured that the `<FrameMetadata>` component uses the `name` property instead of the `property` property to set the type of metadata. Both options are technically correct, but historically, using `name` is more accurate.

- **feat**: renamed the component from `OnchainName` to `Name` in our Identity Kit. This is a breaking changes. The purpose of the rename is to simplify and enhance clarity. By @alvaroraminelli #86
- **fix**: ensured that the `<FrameMetadata>` component uses the `name` property instead of the `property` property to set the type of metadata. Both options are technically correct, but historically, using `name` is more accurate. dc6f33d
- **feat**: renamed the component from `OnchainName` to `Name` in our Identity Kit. This is a breaking changes. The purpose of the rename is to simplify and enhance clarity. By @alvaroraminelli #86

BREAKING CHANGES
BREAKING CHANGES

To enhance usability and intuitiveness, the component name has been simplified. `OnchainName` is now renamed to `Name`.
To enhance usability and intuitiveness, the component name has been simplified. `OnchainName` is now renamed to `Name`.

Before
Before

```ts
import { OnchainName } from '@coinbase/onchainkit';
```ts
import { OnchainName } from '@coinbase/onchainkit';

...
<OnchainName address="0x1234">
```
...
<OnchainName address="0x1234">
```

After
After

```ts
import { Name } from '@coinbase/onchainkit';
```ts
import { Name } from '@coinbase/onchainkit';

...
<Name address="0x1234">
```
...
<Name address="0x1234">
```

## 0.4.5

Expand Down
85 changes: 69 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
<a href="https://www.npmjs.com/package/@coinbase/onchainkit">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://img.shields.io/npm/v/@coinbase/onchainkit?colorA=21262d&colorB=21262d&style=flat">
<img src="https://img.shields.io/npm/v/viem?colorA=f6f8fa&colorB=f6f8fa&style=flat" alt="Version">
<img src="https://img.shields.io/npm/v/@coinbase/onchainkit?colorA=f6f8fa&colorB=f6f8fa&style=flat" alt="Version">
</picture>
</a>
<a href="https://github.com/coinbase/onchainkit/blob/main/LICENSE.md">
Expand Down Expand Up @@ -93,8 +93,13 @@ export default function HomePage() {
label: 'Tell me the story',
},
{
label: 'Redirect to cute dog pictures',
action: 'link',
label: 'Link to Google',
target: 'https://www.google.com'
},
{
action: 'post_redirect',
label: 'Redirect to cute pictures',
},
]}
image="https://zizzamia.xyz/park-1.png"
Expand All @@ -111,10 +116,16 @@ export default function HomePage() {
**@Props**

```ts
type Button = {
label: string;
action?: 'post' | 'post_redirect';
};
type Button =
| {
action: 'link' | 'mint';
label: string;
target: string;
}
| {
action?: 'post' | 'post_redirect';
label: string;
};

type InputMetadata = {
text: string;
Expand All @@ -132,15 +143,22 @@ type FrameMetadataType = {
// A period in seconds at which the app should expect the image to update.
refresh_period?: number;
};

type FrameMetadataReact = FrameMetadataType & {
wrapper?: React.ComponentType<any>;
};
```

**@Returns**

```html
<meta name="fc:frame" content="vNext" />
<meta name="fc:frame:button:1" content="Tell me the story" />
<meta name="fc:frame:button:2" content="Redirect to cute dog pictures" />
<meta name="fc:frame:button:2:action" content="post_redirect" />
<meta name="fc:frame:button:2" content="Link to Google" />
<meta name="fc:frame:button:2:action" content="link" />
<meta name="fc:frame:button:2:target" content="https://www.google.com" />
<meta name="fc:frame:button:3" content="Redirect to cute pictures" />
<meta name="fc:frame:button:3:action" content="post_redirect" />
<meta name="fc:frame:image" content="https://zizzamia.xyz/park-1.png" />
<meta name="fc:frame:input:text" content="Tell me a boat story" />
<meta name="fc:frame:post_url" content="https://zizzamia.xyz/api/frame" />
Expand Down Expand Up @@ -185,10 +203,16 @@ export async function POST(req: NextRequest): Promise<Response> {
**@Param**

```ts
type Button = {
label: string;
action?: 'post' | 'post_redirect';
};
type Button =
| {
action: 'link' | 'mint';
label: string;
target: string;
}
| {
action?: 'post' | 'post_redirect';
label: string;
};

type InputMetadata = {
text: string;
Expand Down Expand Up @@ -344,10 +368,16 @@ export default function Page() {
**@Param**

```ts
type Button = {
label: string;
action?: 'post' | 'post_redirect';
};
type Button =
| {
action: 'link' | 'mint';
label: string;
target: string;
}
| {
action?: 'post' | 'post_redirect';
label: string;
};

type InputMetadata = {
text: string;
Expand Down Expand Up @@ -403,6 +433,29 @@ type UseName = {
};
```

### Avatar

The `Avatar` component is used to display ENS avatar associated with Ethereum addresses. When an ENS avatar is not available, it defaults to blue color avatar.

```tsx
import { Avatar } from '@coinbase/onchainkit';

<Avatar address="0x1234567890abcdef1234567890abcdef12345678" />;
```

**@Props**

```ts
type UseAvatar = {
// Ethereum address to be resolved from ENS.
address: Address;
// Optional CSS class for custom styling.
className?: string;
// Additional HTML attributes for the span element.
props?: React.HTMLAttributes<HTMLSpanElement>;
};
```

### hasVerifiedAttestations

Checks if the specified address has verified attestations for the given chain and expected schemas.
Expand Down
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@coinbase/onchainkit",
"version": "0.5.0",
"version": "0.5.2",
"repository": "https://github.com/coinbase/onchainkit.git",
"license": "MIT",
"scripts": {
Expand All @@ -22,7 +22,7 @@
"graphql-request": "^6",
"react": "^18",
"react-dom": "^18",
"viem": "^2.5.0"
"viem": "^2.7.0"
},
"devDependencies": {
"@changesets/changelog-github": "^0.4.8",
Expand All @@ -43,7 +43,7 @@
"rimraf": "^5.0.5",
"ts-jest": "^29.1.2",
"typescript": "~5.3.3",
"viem": "^2.5.0",
"viem": "^2.7.0",
"yarn": "^1.22.21"
},
"publishConfig": {
Expand Down
88 changes: 88 additions & 0 deletions src/components/Avatar.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/**
* @jest-environment jsdom
*/
import React from 'react';
import { render, screen, waitFor } from '@testing-library/react';
import { Avatar } from './Avatar';
import { useAvatar } from '../hooks/useAvatar';
import { useName } from '../hooks/useName';

import '@testing-library/jest-dom';

jest.mock('../hooks/useName', () => ({
useName: jest.fn(),
}));

jest.mock('../hooks/useAvatar', () => ({
useAvatar: jest.fn(),
}));

describe('Avatar Component', () => {
beforeEach(() => {
jest.clearAllMocks();
});

it('should display loading indicator when loading', async () => {
(useAvatar as jest.Mock).mockReturnValue({ ensAvatar: null, isLoading: true });
(useName as jest.Mock).mockReturnValue({ ensName: null, isLoading: true });

render(<Avatar address="0x123" />);

await waitFor(() => {
const svgElement = screen.getByTestId('avatar-loading-svg');
expect(svgElement).toBeInTheDocument();
});
});

it('should display default avatar when no ENS name or avatar is available', async () => {
(useAvatar as jest.Mock).mockReturnValue({ ensAvatar: null, isLoading: false });
(useName as jest.Mock).mockReturnValue({ ensName: null, isLoading: false });

render(<Avatar address="0x123" />);

await waitFor(() => {
const defaultAvatarElement = screen.getByTestId('avatar-default-svg');
expect(defaultAvatarElement).toBeInTheDocument();
});
});

it('should display ENS avatar when available', async () => {
(useAvatar as jest.Mock).mockReturnValue({ ensAvatar: 'avatar_url', isLoading: false });
(useName as jest.Mock).mockReturnValue({ ensName: 'ens_name', isLoading: false });

render(<Avatar address="0x123" className="custom-class" />);

await waitFor(() => {
const imgElement = screen.getByRole('img');
expect(imgElement).toHaveAttribute('src', 'avatar_url');
expect(imgElement).toHaveAttribute('alt', 'ens_name');
expect(imgElement).toHaveClass('custom-class');
});
});

it('renders custom loading component when provided', () => {
(useAvatar as jest.Mock).mockReturnValue({ ensAvatar: null, isLoading: true });
(useName as jest.Mock).mockReturnValue({ ensName: null, isLoading: true });

const CustomLoadingComponent = <div data-testid="custom-loading">Loading...</div>;

render(<Avatar address="0x123" loadingComponent={CustomLoadingComponent} />);

const customLoadingElement = screen.getByTestId('custom-loading');
expect(customLoadingElement).toBeInTheDocument();
expect(customLoadingElement).toHaveTextContent('Loading...');
});

it('renders custom default component when no ENS name or avatar is available', () => {
(useAvatar as jest.Mock).mockReturnValue({ ensAvatar: null, isLoading: false });
(useName as jest.Mock).mockReturnValue({ ensName: null, isLoading: false });

const CustomDefaultComponent = <div data-testid="custom-default">Default Avatar</div>;

render(<Avatar address="0x123" defaultComponent={CustomDefaultComponent} />);

const customDefaultElement = screen.getByTestId('custom-default');
expect(customDefaultElement).toBeInTheDocument();
expect(customDefaultElement).toHaveTextContent('Default Avatar');
});
});
Loading

0 comments on commit aaf4eb5

Please sign in to comment.