Skip to content

Commit

Permalink
Add Snaps documentation for MetaMask Extension 12.6 updates (#1715)
Browse files Browse the repository at this point in the history
* Add optional context param to snap_updateInterface

This closes #1673

* Update API examples for interfaces to use JSX

* Add Snaps Avatar component

This closes #1701

* Update Address component

This closes #1711

* Add 'valid' to avatar prop

* Add min, max, and step props to Snaps Input component

This fixes #1702

* Add size prop for Snaps Heading component

This fixes #1703

* Add metamask scheme for Snaps Link component

This fixes #1704

* Update Snaps Row component to include Link as a possible child

Fixes #1705

* Add Address component to children of Snaps Link component

Fixes #1706

* Update What's New

Also fix a couple missing indents

* Correct the metamask scheme URL for Snap home page

Also clarify that it leads to the Snap's settings if it does not have a home page, and what to expect when testing.

* Line breaks

* Correct information for local metamask: URLs

* edits

---------

Co-authored-by: Alexandra Tran <[email protected]>
  • Loading branch information
Montoya and alexandratran authored Nov 16, 2024
1 parent 6c7fe31 commit 2fe6af6
Show file tree
Hide file tree
Showing 3 changed files with 150 additions and 51 deletions.
5 changes: 3 additions & 2 deletions docs/whats-new.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,13 @@ of the [MetaMask developer page](https://metamask.io/developer/).

## November 2024

- Updated Snaps [Custom UI documentation](/snaps/features/custom-ui/) for MetaMask Extension version 12.6.
([#1715](https://github.com/MetaMask/metamask-docs/pull/1715))
- Added tutorial for
[creating a simple Starknet dapp](/wallet/how-to/use-non-evm-networks/starknet/create-a-simple-starknet-dapp).
([#1656](https://github.com/MetaMask/metamask-docs/pull/1656))
- Documented Snaps [`Card`](/snaps/features/custom-ui/#card) and [`Section`](/snaps/features/custom-ui/#section) UI components.
([#1707](https://github.com/MetaMask/metamask-docs/pull/1707) and
[#1700](https://github.com/MetaMask/metamask-docs/pull/1700))
([#1707](https://github.com/MetaMask/metamask-docs/pull/1707)) ([#1700](https://github.com/MetaMask/metamask-docs/pull/1700))

## October 2024

Expand Down
143 changes: 124 additions & 19 deletions snaps/features/custom-ui/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ description: Display custom user interface components using JSX.
sidebar_position: 4
---

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

# Custom UI

You can display custom user interface (UI) JSX components using the
Expand All @@ -15,7 +18,9 @@ implementing the following features:
- [Signature insights](../signature-insights.md)

:::note
JSX is supported in the MetaMask extension and Flask version 12 and later. New UI components will be added as JSX components. The previous function-based library is deprecated.
JSX is supported in the MetaMask extension and Flask version 12 and later.
New UI components will be added as JSX components.
The previous function-based library is deprecated.
:::

To use custom UI, first install [`@metamask/snaps-sdk`](https://github.com/MetaMask/snaps/tree/main/packages/snaps-sdk)
Expand All @@ -27,7 +32,8 @@ yarn add @metamask/snaps-sdk

Then, whenever you're required to return a custom UI component, import the components from the
SDK at `@metamask/snaps-sdk/jsx` and build your UI with them.
For example, to display a [`Box`](#box) using [`snap_dialog`](../../reference/snaps-api.md#snap_dialog):
For example, to display a [`Box`](#box) using
[`snap_dialog`](../../reference/snaps-api.md#snap_dialog):

```javascript title="index.jsx"
import { Box, Heading, Text } from "@metamask/snaps-sdk/jsx";
Expand Down Expand Up @@ -56,12 +62,21 @@ The following custom UI components are available:

### `Address`

Outputs a formatted text field for an Ethereum address.
The address is automatically displayed with a jazzicon and truncated value.
Hovering the address shows the full value in a tooltip.
Outputs a formatted text field for a blockchain address.
The address is automatically displayed with a [Jazzicon](https://www.npmjs.com/package/@metamask/jazzicon)
and truncated value.
Hovering over the address shows the full value in a tooltip.

#### Props

- `address`: `string` - A valid Ethereum address, starting with `0x`, or a valid
[CAIP-10](https://github.com/ChainAgnostic/CAIPs/blob/main/CAIPs/caip-10.md) address.

#### Example

<Tabs>
<TabItem value="Ethereum address">

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

Expand All @@ -88,6 +103,59 @@ await snap.request({
</div>
</div>
</TabItem>
<TabItem value="CAIP-10 address">
```javascript title="index.jsx"
import { Box, Heading, Address } from "@metamask/snaps-sdk/jsx";

await snap.request({
method: "snap_dialog",
params: {
type: "alert",
content: (
<Box>
<Heading>The following is an Ethereum address</Heading>
<Address address="eip155:1:0x1234567890123456789012345678901234567890" />
<Heading>The following is a Bitcoin address</Heading>
<Address address="bip122:000000000019d6689c085ae165831e93:128Lkh3S7CkDTBZ8W7BbpsN3YYizJMp8p6" />
</Box>
),
},
});
```
</TabItem>
</Tabs>
### `Avatar`
Outputs a [Jazzicon](https://www.npmjs.com/package/@metamask/jazzicon) for an address.
:::note
MetaMask automatically calculates checksums for EVM addresses (`eip155:`).
Addresses for other namespaces are not validated; you should validate them in your Snap.
:::
#### Props
- `address`: `string` - A valid [CAIP-10](https://github.com/ChainAgnostic/CAIPs/blob/main/CAIPs/caip-10.md) address.
#### Example
```js
export const onHomePage: OnHomePageHandler = async () => {
return {
content: (
<Box>
<Avatar address="eip155:1:0x1234567890123456789012345678901234567890" />
<Avatar address="bip122:000000000019d6689c085ae165831e93:128Lkh3S7CkDTBZ8W7BbpsN3YYizJMp8p6" />
</Box>
),
};
};
```
### `Bold`
Outputs bold text.
Expand Down Expand Up @@ -166,8 +234,8 @@ For use in [interactive UI](interactive-ui.md).
- `type` - (Optional) The type of button.
Possible values are `"button"` and `"submit"`.
The default is `"button"`.
- `name`: `string` - (Optional) The name that will be sent to [`onUserInput`](../../reference/entry-points.md#onuserinput)
when a user selects the button.
- `name`: `string` - (Optional) The name that will be sent to
[`onUserInput`](../../reference/entry-points.md#onuserinput) when a user selects the button.
- `variant` - (Optional) Determines the appearance of the button.
Possible values are `"primary"` and `"destructive"`.
The default is `"primary"`.
Expand Down Expand Up @@ -209,7 +277,8 @@ Outputs a card component which is used to display values in a card structure.
:::info
Unlike many `Card` components from other UI libraries, the Snaps `Card` does not have any shape.
It is only used for layout. To give a shape to a `Card`, wrap it in a [`Section`](#section) component.
It is only used for layout. To give a shape to a `Card`, wrap it in a [`Section`](#section)
component.
:::
#### Props
Expand Down Expand Up @@ -305,7 +374,8 @@ Outputs a read-only text field with a copy-to-clipboard shortcut.
#### Props
- `value`: `string` - The value to copy when the user clicks on the copyable element.
- `sensitive`: `boolean` - (Optional) Indicates whether the value is sensitive. If `true`, the value will be hidden when the user is not interacting with the copyable element.
- `sensitive`: `boolean` - (Optional) Indicates whether the value is sensitive. If `true`, the
value will be hidden when the user is not interacting with the copyable element.
#### Example
Expand Down Expand Up @@ -412,9 +482,11 @@ Outputs a form field, wrapping an element to give it a label and optional error.
#### Props
- `label`: `string` - The label for the wrapped element.
- `error`: `string` - (Optional) Any error for the wrapped element. Setting this changes the style of the wrapped element to show that there is an error.
- `error`: `string` - (Optional) Any error for the wrapped element. Setting this changes the style
of the wrapped element to show that there is an error.
- `children` - The element to be wrapped.
This can be a [`Dropdown`](#dropdown), [`Input`](#input), [`Selector`](#selector), or [`RadioGroup`](#radiogroup) component.
This can be a [`Dropdown`](#dropdown), [`Input`](#input), [`Selector`](#selector), or
[`RadioGroup`](#radiogroup) component.
#### Example
Expand Down Expand Up @@ -508,8 +580,8 @@ Outputs a form for use in [interactive UI](interactive-ui.md).
#### Props
- `name`: `string` - The name that will be sent to [`onUserInput`](../../reference/entry-points.md#onuserinput)
when a user interacts with the form.
- `name`: `string` - The name that will be sent to
[`onUserInput`](../../reference/entry-points.md#onuserinput) when a user interacts with the form.
- `children`: `array` - An array of [`Input`](#input) or [`Button`](#button) components.
#### Example
Expand Down Expand Up @@ -549,6 +621,11 @@ await snap.request({
Outputs a heading.
This is useful for [`Box`](#box) titles.
#### Props
- `size`: `string` - (Optional) The size of the heading. Possible values are `"sm"`, `"md"`, and
`"lg"`. The default is `"sm"`.
#### Example
```javascript title="index.jsx"
Expand Down Expand Up @@ -616,7 +693,8 @@ This component takes an inline SVG.
It does not support remote URLs.
You can import SVG, PNG, and JPEG files using an import statement.
These files are automatically imported as SVG strings, so you can pass them directly to the `Image` component.
These files are automatically imported as SVG strings, so you can pass them directly to the
`Image` component.
The SVG is rendered within an `<img>` tag, which prevents JavaScript or interaction events from
being supported.
Expand Down Expand Up @@ -667,13 +745,20 @@ Outputs an input component for use in [interactive UI](interactive-ui.md).
#### Props
- `name`: `string` - The name that will be used as a key to the event sent to
[`onUserInput`](../../reference/entry-points.md#onuserinput) when the containing form is submitted.
[`onUserInput`](../../reference/entry-points.md#onuserinput) when the containing form is
submitted.
- `type` - (Optional) The type of input.
Possible values are `"text"`, `"number"`, and `"password"`.
The default is `"text"`.
- `placeholder`: `string` - (Optional) The text displayed when the input is empty.
- `label`: `string` - (Optional) The text displayed alongside the input to label it.
- `value`: `string` - (Optional) The default value of the input.
- `min`: `string` - (Optional) The minimum value of the input field. Only applicable to the input
type `"number"`.
- `max`: `string` - (Optional) The maximum value of the input field. Only applicable to the input
type `"number"`.
- `step`: `string` - (Optional) The step value of the input field. Only applicable to the input
type `"number"`.
#### Example
Expand Down Expand Up @@ -738,8 +823,28 @@ Outputs a clickable link.
#### Props
- `href`: `string` - The URL to point to. Supported schemes are `https:` and `mailto:`. `http:` is not allowed.
- `children`: `Array<string | Bold | Italic>` - The link text.
- `href`: `string` - The URL to point to. Supported schemes are `https:`, `mailto:`, and
`metamask:`. `http:` is not allowed.
- `children`: `Array<string | Bold | Italic | Address>` - The link text, or an
[`Address`](#address).
#### About `metamask:` URLs
A Snap can link to the following screens using the `metamask:` scheme:
- `metamask://client/` - Leads to the main screen of MetaMask.
- `metamask://snap/[Snap ID]/home/` - Leads to the Snap's
[home page](../custom-ui/home-pages.md), or the Snap's settings page if it does not have a home
page. Valid Snap IDs are npm IDs beginning with `npm:`, such as
`metamask://snap/npm:@consensys/starknet-snap/home`, or `local:`, such as
`metamask://snap/local:http://localhost:8080/home`. Consider using
[environment variables](../../how-to/use-environment-variables.md) so you can have different
Snap IDs for local testing and production.

:::warning
MetaMask will throw an error if the URL is not valid or if the URL leads to a Snap that is not
installed.
:::

#### Example

Expand Down Expand Up @@ -813,8 +918,8 @@ Outputs a row with a label and value, which can be used for key-value data.
- `variant` - (Optional) The variant of the label.
Possible values are `"default"`, `"error"`, and `"warning"`.
The default is `"default"`.
- `children` - The value of the row, which can be a [`Text`](#text), [`Image`](#image), or
[`Address`](#address) component.
- `children` - The value of the row, which can be a [`Text`](#text), [`Image`](#image),
[`Address`](#address), or [`Link`](#link) component.

#### Example

Expand Down
53 changes: 23 additions & 30 deletions snaps/reference/snaps-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -914,13 +914,12 @@ The interface's ID to be used in [`snap_dialog`](#snap_dialog), returned from
const interfaceId = await snap.request({
method: "snap_createInterface",
params: {
ui: panel([
heading("Interactive interface"),
button({
value: "Click me",
name: "interactive-button",
}),
]),
ui: (
<Box>
<Heading>Interactive interface</Heading>
<Button name="interactive-button">Click me</Button>
</Box>
)
},
})

Expand Down Expand Up @@ -956,26 +955,16 @@ An object where each top-level property can be one of the following:
const interfaceId = await snap.request({
method: "snap_createInterface",
params: {
ui: panel([
heading("Interactive UI Example Snap"),
// A top-level input.
input({
name: "top-level-input",
placeholder: "Enter something",
}),
// A top-level form...
form({
name: "example-form",
children: [
// ...with a nested input.
input({
name: "nested-input",
placeholder: "Enter something",
}),
button("Submit", ButtonType.Submit, "submit"),
],
}),
]),
ui: (
<Box>
<Heading>Interactive UI Example Snap</Heading>
<Input name="top-level-input" placeholder="Enter something"/>
<Form name="example-form">
<Input name="nested-input" placeholder="Enter something"/>
<Button type="submit">Submit</Button>
</Form>
</Box>
)
},
})

Expand Down Expand Up @@ -1025,6 +1014,7 @@ An object containing:
- `id` - The ID of the interface to be updated, usually received in the
[`onUserInput`](./entry-points.md#onuserinput) entry point.
- `ui` - The [custom UI](../features/custom-ui/index.md) to create.
- `context` - (Optional) A custom context object that will be passed to [`onUserInput`](./entry-points.md#onuserinput) when the user interacts with the interface. Passing this parameter will update the context object for the interface.

#### Example

Expand All @@ -1036,9 +1026,12 @@ export function onUserInput({ id, event }) {
method: "snap_updateInterface",
params: {
id,
ui: panel([
heading("New interface"),
]),
ui: (
<Box>
<Heading>New interface</Heading>
<Text>This interface has been updated</Text>
</Box>
)
},
});
};
Expand Down

0 comments on commit 2fe6af6

Please sign in to comment.