Skip to content

Commit

Permalink
Translate Custom UI examples to JSX (#1348)
Browse files Browse the repository at this point in the history
* Translate Custom UI examples to JSX

* Add flaskOnly prop for TabItem

* Import Tabs and TabItem components

* Add Dropdown JSX component

* Adjust description of JSX Link

* .js > .tsx

* .tsx > .jsx

* Add Field component docs

* Update snaps/features/custom-ui/with-jsx.md

Co-authored-by: Maarten Zuidhoorn <maarten@zuidhoorn.com>

* JSX is not flask-only, functions is deprecated

* document JSX Box props

* edit custom ui with jsx

* update what's new

* Replace single-quote imports with double quotes

* Add notes for version 12+

And fix link to tx insights feature

---------

Co-authored-by: Christian Montoya <christian.montoya@consensys.net>
Co-authored-by: Maarten Zuidhoorn <maarten@zuidhoorn.com>
Co-authored-by: Alexandra Tran <alexandratran@protonmail.com>
Co-authored-by: Alexandra Carrillo <12214231+alexandratran@users.noreply.github.com>
  • Loading branch information
5 people authored Jul 31, 2024
1 parent 6411f85 commit c56eaf5
Show file tree
Hide file tree
Showing 24 changed files with 1,604 additions and 101 deletions.
2 changes: 2 additions & 0 deletions docs/whats-new.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ of the [MetaMask developer page](https://metamask.io/developer/).

## June 2024

- Documented [Snaps custom UI with JSX](/snaps/features/custom-ui/with-jsx).
([#1348](https://github.com/MetaMask/metamask-docs/pull/1348))
- Updated [React dapp with global state tutorial](/wallet/tutorials/react-dapp-global-state) with
instructions for EIP-6963.
([#1330](https://github.com/MetaMask/metamask-docs/pull/1330))
Expand Down
6 changes: 3 additions & 3 deletions services/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ sidebar_label: Introduction
sidebar_position: 1
---

import CodeTerminal from '@site/src/components/CodeTerminal/CodeTerminal.jsx';
import SectionAPIs from '@site/src/components/Sections/SectionAPIs.jsx';
import SectionNetworks from '@site/src/components/Sections/SectionNetworks.jsx';
import CodeTerminal from "@site/src/components/CodeTerminal/CodeTerminal.jsx";
import SectionAPIs from "@site/src/components/Sections/SectionAPIs.jsx";
import SectionNetworks from "@site/src/components/Sections/SectionNetworks.jsx";

# Build and scale your dapp using services

Expand Down
Binary file added snaps/assets/custom-ui-box.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added snaps/assets/custom-ui-dropdown-active.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added snaps/assets/custom-ui-dropdown.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added snaps/assets/custom-ui-field.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
43 changes: 42 additions & 1 deletion snaps/features/cron-jobs.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ description: Schedule periodic actions for your users.
sidebar_position: 1
---

import Tabs from "@theme/Tabs";
import TabItem from "@theme/TabItem";

# Cron jobs

You can schedule actions to run periodically at fixed times or intervals, also known as "cron jobs."
Expand Down Expand Up @@ -40,8 +43,43 @@ Expose an [`onCronjob`](../reference/entry-points.md#oncronjob) entry point, whi
the specified schedule with the requests defined in the `endowment:cronjob` permission.
The following example handles the `execute` method specified in the previous example:

<Tabs>

<TabItem value="JSX">

```tsx title="index.tsx"
import type { OnCronjobHandler } from "@metamask/snaps-sdk";
import { Box, Heading, Text } from "@metamask/snaps-sdk/jsx";

export const onCronjob: OnCronjobHandler = async ({ request }) => {
switch (request.method) {
case "execute":
// Cron jobs can execute any method that is available to the Snap.
return snap.request({
method: "snap_dialog",
params: {
type: "alert",
content: (
<Box>
<Heading>Cron job</Heading>
<Text>This dialog was triggered by a cron job.</Text>
</Box>
),
},
});

default:
throw new Error("Method not found.");
}
};
```

</TabItem>
<TabItem value="Functions" deprecated>

```typescript title="index.ts"
import type { OnCronjobHandler } from "@metamask/snaps-sdk"
import type { OnCronjobHandler } from "@metamask/snaps-sdk";
import { panel, heading, text } from "@metamask/snaps-sdk";

export const onCronjob: OnCronjobHandler = async ({ request }) => {
switch (request.method) {
Expand All @@ -64,6 +102,9 @@ export const onCronjob: OnCronjobHandler = async ({ request }) => {
}
```

</TabItem>
</Tabs>

:::tip Access data from cron jobs
When accessing [encrypted data](data-storage.md#2-use-encrypted-storage) from cron jobs, MetaMask
requires the user to enter their password if the wallet is locked.
Expand Down
91 changes: 91 additions & 0 deletions snaps/features/custom-ui/dialogs.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ description: Display custom alert, confirmation, or prompt screens in MetaMask.
sidebar_position: 2
---

import Tabs from "@theme/Tabs";
import TabItem from "@theme/TabItem";

# Dialogs

You can display a dialog in the MetaMask UI using the
Expand Down Expand Up @@ -35,6 +38,31 @@ To display an alert that can only be acknowledged, call
[`snap_dialog`](../../reference/snaps-api.md#snap_dialog) with `type: "alert"`.
The following example displays custom UI that alerts the user when something happens in the system:

<Tabs>
<TabItem value="JSX">

```tsx title="index.tsx"
import { Box, Text, Heading } from "@metamask/snaps-sdk/jsx";

await snap.request({
method: "snap_dialog",
params: {
type: "alert",
content: (
<Box>
<Heading>Something happened in the system</Heading>
<Text>The thing that happened is...</Text>
</Box>
),
},
});

// Code that should execute after the alert has been acknowledged.
```

</TabItem>
<TabItem value="Functions" deprecated>

```javascript title="index.js"
import { panel, text, heading } from "@metamask/snaps-sdk"

Expand All @@ -52,6 +80,10 @@ await snap.request({
// Code that should execute after the alert has been acknowledged.
```

</TabItem>
</Tabs>


<p align="center">
<img src={require("../../assets/alert-dialog.png").default} alt="Alert dialog example" width="360px" style={{border: "1px solid #DCDCDC"}} />
</p>
Expand All @@ -63,6 +95,33 @@ To display a confirmation that can be accepted or rejected, call
The following example displays custom UI that asks the user to confirm whether they would like to
take an action:

<Tabs>
<TabItem value="JSX">

```tsx title="index.tsx"
import { Box, Text, Heading } from "@metamask/snaps-sdk/jsx";

const result = await snap.request({
method: "snap_dialog",
params: {
type: "confirmation",
content: (
<Box>
<Heading>Would you like to take the action?</Heading>
<Text>The action is...</Text>
</Box>
),
},
});

if (result === true) {
// Do the action.
}
```

</TabItem>
<TabItem value="Functions" deprecated>

```javascript title="index.js"
import { panel, text, heading } from "@metamask/snaps-sdk"

Expand All @@ -82,6 +141,9 @@ if (result === true) {
}
```

</TabItem>
</Tabs>

<p align="center">
<img src={require("../../assets/confirmation-dialog.png").default} alt="Confirmation dialog example" width="360px" style={{border: "1px solid #DCDCDC"}} />
</p>
Expand All @@ -94,6 +156,32 @@ Prompt dialogs also accept a `placeholder` value that displays in the input fiel

The following example displays custom UI that prompts the user to enter a wallet address:

<Tabs>
<TabItem value="JSX">

```tsx title="index.tsx"
import { Box, Text, Heading } from "@metamask/snaps-sdk/jsx";

const walletAddress = await snap.request({
method: "snap_dialog",
params: {
type: "prompt",
content: (
<Box>
<Heading>What is the wallet address?</Heading>
<Text>Please enter the wallet address to be monitored</Text>
</Box>
),
placeholder: "0x123...",
},
});

// walletAddress will be a string containing the address entered by the user.
```

</TabItem>
<TabItem value="Functions" deprecated>

```javascript title="index.js"
import { panel, text, heading } from "@metamask/snaps-sdk"

Expand All @@ -112,6 +200,9 @@ const walletAddress = await snap.request({
// walletAddress will be a string containing the address entered by the user.
```

</TabItem>
</Tabs>

<p align="center">
<img src={require("../../assets/prompt-dialog.png").default} alt="Prompt dialog example" width="360px" style={{border: "1px solid #DCDCDC"}} />
</p>
Expand Down
28 changes: 28 additions & 0 deletions snaps/features/custom-ui/home-pages.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ description: Display a dedicated UI page in MetaMask for your Snap.
sidebar_position: 3
---

import Tabs from "@theme/Tabs";
import TabItem from "@theme/TabItem";

# Home pages

You can display a dedicated UI, or "home page," for your Snap within MetaMask.
Expand Down Expand Up @@ -32,6 +35,28 @@ MetaMask calls this method when a user selects your Snap name in the Snaps menu.

The following example displays custom UI that welcomes the user to the Snap's home page:

<Tabs>
<TabItem value="JSX">

```tsx title="index.tsx"
import type { OnHomePageHandler } from "@metamask/snaps-sdk";
import { Box, Heading, Text } from "@metamask/snaps-sdk/jsx";

export const onHomePage: OnHomePageHandler = async () => {
return {
content: (
<Box>
<Heading>Hello world!</Heading>
<Text>Welcome to my Snap home page!</Text>
</Box>
),
};
};
```

</TabItem>
<TabItem value="Functions" deprecated>

```typescript title="index.ts"
import type { OnHomePageHandler } from "@metamask/snaps-sdk"
import { panel, text, heading } from "@metamask/snaps-sdk"
Expand All @@ -46,6 +71,9 @@ export const onHomePage: OnHomePageHandler = async () => {
}
```

</TabItem>
</Tabs>

<p align="center">
<img src={require("../../assets/home-page.png").default} alt="Home page example" width="360px" style={{border: "1px solid #DCDCDC"}} />
</p>
Expand Down
9 changes: 7 additions & 2 deletions snaps/features/custom-ui/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,18 @@ sidebar_position: 4

# Custom UI

:::caution
This version of custom UI is deprecated. If you're building a new Snaps project,
use [custom UI with JSX](./with-jsx). JSX is supported in MetaMask Extension and Flask version 12+.
:::

You can display custom user interface (UI) components using the
[`@metamask/snaps-sdk`](https://github.com/MetaMask/snaps/tree/main/packages/snaps-sdk) module when
implementing the following features:

- [Dialogs](dialogs.md)
- [Home pages](home-pages.md)
- [Transaction insights](../../reference/entry-points.md#ontransaction)
- [Transaction insights](../transaction-insights.md)
- [Signature insights](../signature-insights.md)

To use custom UI, first install [`@metamask/snaps-sdk`](https://github.com/MetaMask/snaps/tree/main/packages/snaps-sdk)
Expand Down Expand Up @@ -309,7 +314,7 @@ An object containing:
#### Example

```js
import { input, form } from "@metamask/snaps-sdk"
import { button, input, form } from "@metamask/snaps-sdk";

const interfaceId = await snap.request({
method: "snap_createInterface",
Expand Down
8 changes: 8 additions & 0 deletions snaps/features/custom-ui/interactive-ui.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,14 @@ The following interactive UI components are available:
- [`form`](index.md#form)
- [`input`](index.md#input)

The following interactive UI JSX components are available:

- [`Button`](with-jsx.md#button)
- [`Dropdown`](with-jsx.md#dropdown)
- [`Field`](with-jsx.md#field)
- [`Form`](with-jsx.md#form)
- [`Input`](with-jsx.md#input)

## Create an interactive interface

Create an interactive interface using the
Expand Down
Loading

0 comments on commit c56eaf5

Please sign in to comment.