diff --git a/docs/whats-new.md b/docs/whats-new.md
index 9a26b94691..75e5e38654 100644
--- a/docs/whats-new.md
+++ b/docs/whats-new.md
@@ -11,6 +11,9 @@ of the [MetaMask developer page](https://metamask.io/developer/).
## September 2024
+- Documented new [Snaps custom UI JSX components](/snaps/features/custom-ui) for Flask
+ version 12.4, and removed documentation for deprecated function-based library.
+ ([#1540](https://github.com/MetaMask/metamask-docs/pull/1540))
- Documented [Snaps user-defined components](/snaps/features/custom-ui/user-defined-components).
([#1557](https://github.com/MetaMask/metamask-docs/pull/1557))
- Updated [Android SDK documentation](/wallet/how-to/use-sdk/mobile/android) with convenience
diff --git a/snaps/assets/custom-ui-checkbox.png b/snaps/assets/custom-ui-checkbox.png
new file mode 100644
index 0000000000..ff803115f8
Binary files /dev/null and b/snaps/assets/custom-ui-checkbox.png differ
diff --git a/snaps/assets/custom-ui-file-input.png b/snaps/assets/custom-ui-file-input.png
new file mode 100644
index 0000000000..7f69567c54
Binary files /dev/null and b/snaps/assets/custom-ui-file-input.png differ
diff --git a/snaps/assets/custom-ui-heading.png b/snaps/assets/custom-ui-heading.png
index b37b412321..8aee9f21cc 100644
Binary files a/snaps/assets/custom-ui-heading.png and b/snaps/assets/custom-ui-heading.png differ
diff --git a/snaps/assets/custom-ui-icon.png b/snaps/assets/custom-ui-icon.png
new file mode 100644
index 0000000000..ef6dbe6a3d
Binary files /dev/null and b/snaps/assets/custom-ui-icon.png differ
diff --git a/snaps/assets/custom-ui-radio-group.png b/snaps/assets/custom-ui-radio-group.png
new file mode 100644
index 0000000000..0004c04f53
Binary files /dev/null and b/snaps/assets/custom-ui-radio-group.png differ
diff --git a/snaps/assets/custom-ui-selector.png b/snaps/assets/custom-ui-selector.png
new file mode 100644
index 0000000000..dc6d9a4457
Binary files /dev/null and b/snaps/assets/custom-ui-selector.png differ
diff --git a/snaps/assets/custom-ui-tooltip.png b/snaps/assets/custom-ui-tooltip.png
new file mode 100644
index 0000000000..6a1e00b1b5
Binary files /dev/null and b/snaps/assets/custom-ui-tooltip.png differ
diff --git a/snaps/assets/home-page.png b/snaps/assets/home-page.png
index 7b07f72d8f..8aee9f21cc 100644
Binary files a/snaps/assets/home-page.png and b/snaps/assets/home-page.png differ
diff --git a/snaps/features/custom-ui/dialogs.md b/snaps/features/custom-ui/dialogs.md
index 80831ad3d3..0cd167e729 100644
--- a/snaps/features/custom-ui/dialogs.md
+++ b/snaps/features/custom-ui/dialogs.md
@@ -3,9 +3,6 @@ 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
@@ -38,9 +35,6 @@ 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:
-
@@ -95,9 +65,6 @@ 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: -
@@ -156,9 +98,6 @@ 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: -
diff --git a/snaps/features/custom-ui/home-pages.md b/snaps/features/custom-ui/home-pages.md index 7fd7fe0285..fe6555b7f8 100644 --- a/snaps/features/custom-ui/home-pages.md +++ b/snaps/features/custom-ui/home-pages.md @@ -3,9 +3,6 @@ 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. @@ -35,9 +32,6 @@ 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: -
diff --git a/snaps/features/custom-ui/index.md b/snaps/features/custom-ui/index.md index 517e9c23f4..02d544ef6f 100644 --- a/snaps/features/custom-ui/index.md +++ b/snaps/features/custom-ui/index.md @@ -1,16 +1,11 @@ --- -description: Display custom user interface components. +description: Display custom user interface components using JSX. 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 +You can display custom user interface (UI) JSX components using the [`@metamask/snaps-sdk`](https://github.com/MetaMask/snaps/tree/main/packages/snaps-sdk) module when implementing the following features: @@ -19,6 +14,10 @@ implementing the following features: - [Transaction insights](../transaction-insights.md) - [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. +::: + To use custom UI, first install [`@metamask/snaps-sdk`](https://github.com/MetaMask/snaps/tree/main/packages/snaps-sdk) using the following command: @@ -27,49 +26,57 @@ yarn add @metamask/snaps-sdk ``` Then, whenever you're required to return a custom UI component, import the components from the -SDK and build your UI with them. -For example, to display a [`panel`](#panel) using [`snap_dialog`](../../reference/snaps-api.md#snap_dialog): +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): -```javascript title="index.js" -import { panel, heading, text } from "@metamask/snaps-sdk" +```javascript title="index.jsx" +import { Box, Heading, Text } from "@metamask/snaps-sdk/jsx"; await snap.request({ method: "snap_dialog", params: { type: "alert", - content: panel([ - heading("Alert heading"), - text("Something happened in the system."), - ]), + content: ( +
+ +
+ +### `Button` Outputs a button that the user can select. For use in [interactive UI](interactive-ui.md). -#### Parameters - -An object containing: +#### Props -- `value`: `string` - The text of the button. -- `buttonType`: `string` - (Optional) Possible values are `button` or `submit`. - The default is `button`. +- `children` - The contents of the button. + This can be text, an [`Image`](#image) component, or an [`Icon`](#icon) component. +- `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. - `variant` - (Optional) Determines the appearance of the button. - Possible values are `primary` or `secondary`. - The default is `primary`. + Possible values are `"primary"` and `"destructive"`. + The default is `"primary"`. #### Example ```javascript -import { button, panel, heading } from "@metamask/snaps-sdk" +import { Box, Heading, Button } from "@metamask/snaps-sdk/jsx"; const interfaceId = await snap.request({ method: "snap_createInterface", params: { - ui: panel([ - heading("Interactive interface"), - button({ - value: "Click me", - name: "interactive-button", - }), - ]), + ui: ( +-### `copyable` +### `Checkbox` + +Outputs a checkbox for use in [interactive UI](interactive-ui.md). + +#### Props + +- `name`: `string` - The name sent to [`onUserInput`](../../reference/entry-points.md#onuserinput). +- `checked`: `boolean` - (Optional) Whether the checkbox is checked. +- `label`: `string` - (Optional) The label for the checkbox. +- `variant` - (Optional) The variant of the checkbox. + Possible values are `"default"` and `"toggle"`. + The default is `"default"`. + +#### Example + +```js +import { Checkbox } from "@metamask/snaps-sdk/jsx"; + +const interfaceId = await snap.request({ + method: "snap_createInterface", + params: { + ui: ( +
+ +
+ +### `Copyable` 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. + #### Example -```javascript title="index.js" -import { text, copyable } from "@metamask/snaps-sdk" +```javascript title="index.jsx" +import { Box, Text, Copyable } from "@metamask/snaps-sdk/jsx"; await snap.request({ method: "snap_dialog", params: { type: "alert", - content: panel([ - text("Your address:"), - copyable("0x000000000000000000000000000000000000dEaD"), - ]), + content: ( +-### `divider` +### `Divider` Outputs a horizontal divider. #### Example -```javascript title="index.js" -import type { OnHomePageHandler } from "@metamask/snaps-sdk"; -import { panel, divider, text } from "@metamask/snaps-sdk"; +```javascript title="index.jsx" +import { Box, Heading, Divider, Text } from "@metamask/snaps-sdk/jsx"; module.exports.onHomePage = async () => { return { - content: panel([ - heading("Hello world!"), - divider(), - text("Welcome to my Snap home page!"), - ]), + content: ( +
+ +
+ +### `FileInput` + +Outputs a file input component 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. -- `children`: `array` - An array of [`input`](#input) or [`button`](#button) components. +- `accept`: `string[]` - (Optional) The file types that the file input field accepts. If not +specified, the file input field accepts all file types. For examples of +valid values, see the [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/accept). +- `compact`: `boolean` - (Optional) Whether the file input field is compact. #### Example ```js -import { input, button, form } from "@metamask/snaps-sdk" +import { FileInput } from "@metamask/snaps-sdk/jsx"; + +export const onHomePage = async () => { + const interfaceId = await snap.request({ + method: "snap_createInterface", + params: { + ui: ( ++ +
+ +### `Form` + +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. +- `children`: `array` - An array of [`Input`](#input) or [`Button`](#button) components. + +#### Example + +```js +import { Form, Input, Button } from "@metamask/snaps-sdk/jsx"; const interfaceId = await snap.request({ method: "snap_createInterface", params: { - ui: form({ - name: "form-to-fill", - children: [ - input({ - name: "user-name", - placeholder: "Your name", - }), - button({ - value: "Submit", - buttonType: "submit", - }), - ], - }), + ui: ( + + ), }, -}) +}); await snap.request({ method: "snap_dialog", @@ -222,30 +477,31 @@ await snap.request({ type: "Alert", id: interfaceId, }, -}) +}); ```-### `heading` +### `Heading` Outputs a heading. -This is useful for [`panel`](#panel) titles. +This is useful for [`Box`](#box) titles. #### Example -```javascript title="index.js" -import type { OnHomePageHandler } from "@metamask/snaps-sdk"; -import { panel, heading, text } from "@metamask/snaps-sdk"; +```javascript title="index.jsx" +import { Box, Heading, Text } from "@metamask/snaps-sdk/jsx"; module.exports.onHomePage = async () => { return { - content: panel([ - heading("Hello world!"), - text("Welcome to my Snap home page!"), - ]), + content: ( +
+ +
+ +### `Image` + +Outputs an image. 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 `` tag, which prevents JavaScript or interaction events from being supported. @@ -272,20 +567,26 @@ configuration option to `false`. The default is `true`. ::: +#### Props + +- `src`: `string` - An inline SVG. +- `alt`: `string` - An optional alternative text for the image. + #### Example -```javascript title="index.js" -import type { OnHomePageHandler } from "@metamask/snaps-sdk"; -import { panel, heading, text, image } from "@metamask/snaps-sdk"; +```javascript title="index.jsx" +import { Box, Heading, Text, Image } from "@metamask/snaps-sdk/jsx"; import svgIcon from "./path/to/icon.svg"; module.exports.onHomePage = async () => { return { - content: panel([ - heading("Hello world!"), - text("Welcome to my Snap home page!"), - image(svgIcon), - ]), + content: ( +-:::note -See the [`@metamask/images-example-snap`](https://github.com/MetaMask/snaps/tree/main/packages/examples/packages/images) -package for a full example of implementing images. -::: +### `Italic` + +Outputs italic text. + +#### Example + +```javascript title="index.jsx" +import { Box, Heading, Text, Italic } from "@metamask/snaps-sdk/jsx"; + +await snap.request({ + method: "snap_dialog", + params: { + type: "alert", + content: ( +
- +
-### `row` +### `RadioGroup` -Outputs a row with a label and value, which can be used for key-value data. -The label must be a string. The value can be a child component of type -[`text`](#text) or [`address`](#address). +Outputs a radio group 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. +- `children`: `Radio[]` - One or more `Radio` components, each with a `value` and text child. #### Example -```javascript title="index.js" -import { panel, row, text, address } from "@metamask/snaps-sdk" +```js +import { RadioGroup, Radio } from "@metamask/snaps-sdk/jsx"; -await snap.request({ - method: "snap_dialog", +const interfaceId = await snap.request({ + method: "snap_createInterface", params: { - type: "alert", - content: panel([ - row("Address", address("0x000000000000000000000000000000000000dEaD")), - row("Balance", text("1.78 ETH")), - ]), + ui: ( + + ), }, -}) +}); ```- +
-### `spinner` +### `Row` -Outputs a loading indicator. +Outputs a row with a label and value, which can be used for key-value data. + +#### Props + +- `label`: `string` - The label of the row. +- `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. #### Example -```javascript title="index.js" -import { panel, heading, spinner } from "@metamask/snaps-sdk" +```javascript title="index.jsx" +import { Box, Row, Text, Address } from "@metamask/snaps-sdk/jsx"; await snap.request({ method: "snap_dialog", params: { type: "alert", - content: panel([heading("Please wait..."), spinner()]), + content: ( +- +
-### `text` +### `Selector` -Outputs text. +Outputs a selector 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. +- `title`: `string` - The title of the selector, displayed when the selector is opened. +- `children`: `SelectorOption[]` - One or more `SelectorOption` components, each with a `Card` child. #### Example -```javascript title="index.js" -import type { OnHomePageHandler } from "@metamask/snaps-sdk"; -import { panel, heading, text } from "@metamask/snaps-sdk"; +```js +import { Selector, SelectorOption, Card } from "@metamask/snaps-sdk/jsx"; -module.exports.onHomePage = async () => { - return { - content: panel([ - heading("Hello world!"), - text("Welcome to my Snap home page!"), - ]), - }; -}; +const interfaceId = await snap.request({ + method: "snap_createInterface", + params: { + ui: ( +- +
-## Markdown +### `Spinner` -[`text`](#text) components accept bold and italic inline Markdown. +Outputs a loading indicator. #### Example -```javascript title="index.js" -import { panel, heading, text } from "@metamask/snaps-sdk" +```javascript title="index.jsx" +import { Box, Heading, Spinner } from "@metamask/snaps-sdk/jsx"; await snap.request({ method: "snap_dialog", params: { type: "alert", - content: panel([ - heading("Hello world!"), - text("This is **bold** and this is _italic_."), - ]), + content: ( +- +
-## Links +### `Text` + +Outputs text. + +#### Props + +- `color` - (Optional) The color of the text. + Possible values are `"default"`, "`alternative`", `"muted"`, `"error"`, `"success"`, and `"warning"`. + The default is `"default"`. +- `alignment` - (Optional) The alignment of the text. + Possible values are `"start"`, `"center"`, and `"end"`. + The default is `"start"`. -[`text`](#text) components accept inline links. #### Example -```javascript title="index.js" -import type { OnHomePageHandler } from "@metamask/snaps-sdk"; -import { panel, text } from "@metamask/snaps-sdk"; +```javascript title="index.jsx" +import { Box, Heading, Text } from "@metamask/snaps-sdk/jsx"; module.exports.onHomePage = async () => { return { - content: panel([ - heading("Hello world!"), - text("Download [MetaMask](https://metamask.io)."), - text("Read the MetaMask docs at [](https://docs.metamask.io)."), - ]), + content: ( +- + +
+ +### `Tooltip` + +Outputs a tooltip when the wrapped element is hovered over. + +#### Props + +- `content`: - The content of the tooltip. +- `children`: - The element to wrap. + +#### Example + +```javascript title="index.jsx" +import { Tooltip, Text } from "@metamask/snaps-sdk/jsx"; + +await snap.request({ + method: "snap_dialog", + params: { + type: "alert", + content: ( ++
## Emojis -Text-based components (such as [`heading`](#heading) and [`text`](#text)) accept emojis. +Text-based components (such as [`Heading`](#heading) and [`Text`](#text)) accept emojis. #### Example -```javascript title="index.js" -import { panel, heading, text } from "@metamask/snaps-sdk" +```javascript title="index.jsx" +import { Box, Heading, Text } from "@metamask/snaps-sdk/jsx"; await snap.request({ method: "snap_dialog", params: { type: "alert", - content: panel([ - heading("Hello world!"), - text("This is an apple 🍎 and this is an orange 🍊."), - ]), + content: ( +-## Examples +## User-defined components + +In addition to the components provided by the SDK, you can [define your own components](user-defined-components.md). + +## Upgrade a Snap to use JSX + +If you have a Snap that uses the deprecated function-based custom UI library, follow these +steps to upgrade it to use JSX: + +1. Upgrade dependencies in `packages/snap/package.json`: + + - Upgrade `@metamask/snaps-sdk` to `^6.1.1` or later. + - Upgrade `@metamask/snaps-cli` to `^6.2.1` or later. + - Upgrade `@metamask/snaps-jest` to `^8.2.0` or later. + + Run `yarn install` to install the new versions. + +2. Update `packages/snap/.eslintrc.js`: + + - Add a new section in `overrides` with the following configuration: + ```json + { + "files": ["**/*.ts", "**/*.tsx"], + "extends": ["@metamask/eslint-config-typescript"], + "rules": { + // This allows importing the `Text` JSX component. + "@typescript-eslint/no-shadow": [ + "error", + { + "allow": ["Text"], + }, + ], + }, + } + ``` + - Replace `["*.test.ts"]` with `["*.test.ts", "*.test.tsx"]`. + +3. Update `packages/snap/src/index.ts`, if it will have JSX: + + - Rename the file to `index.tsx`. + - Modify the `input` field in `packages/snap/snap.config.ts` to `src/index.tsx`. + +4. Update `packages/snap/tsconfig.json`: -See the following packages for full examples of implementing custom UI: + - Under `compilerOptions`, add: + ```json + "jsx": "react-jsx", + "jsxImportSource": "@metamask/snaps-sdk" + ``` + - Change the `include` property from `["**/*.ts"]` to `["**/*.ts", "**/*.tsx"]`. -- [`@metamask/dialog-example-snap`](https://github.com/MetaMask/snaps/tree/main/packages/examples/packages/dialogs) -- [`@metamask/transaction-insight-example-snap`](https://github.com/MetaMask/snaps/tree/main/packages/examples/packages/transaction-insights) -- [`@metamask/home-page-example-snap`](https://github.com/MetaMask/snaps/tree/main/packages/examples/packages/home-page) -- [`@metamask/images-example-snap`](https://github.com/MetaMask/snaps/tree/main/packages/examples/packages/images) +5. Replace all custom UI in your code with JSX components, renaming the target files with the `.tsx` extension. diff --git a/snaps/features/custom-ui/interactive-ui.md b/snaps/features/custom-ui/interactive-ui.md index 7eb54e057d..6f0613cdac 100644 --- a/snaps/features/custom-ui/interactive-ui.md +++ b/snaps/features/custom-ui/interactive-ui.md @@ -12,17 +12,11 @@ It allows interfaces returned from [dialogs](dialogs.md), [home pages](home-page The following interactive UI components are available: -- [`button`](index.md#button) -- [`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) +- [`Button`](index.md#button) +- [`Dropdown`](index.md#dropdown) +- [`Field`](index.md#field) +- [`Form`](index.md#form) +- [`Input`](index.md#input) ## Create an interactive interface @@ -37,6 +31,13 @@ If you need to [update the interface](#update-an-interactive-interface) or [get its state](#get-an-interactive-interfaces-state) at a future time, you should store its ID in the Snap's storage. +### Add context to an interface + +You can optionally add context to an interface by passing a `context` object to the +[`snap_createInterface`](../../reference/snaps-api.md#snap_createinterface) method. +This object can contain any data you want to pass to the interface. +This context will be passed to [`onUserInput`](../../reference/entry-points.md#onuserinput) when the user interacts with the interface. + ## Update an interactive interface To update an interactive interface that is still active, use the diff --git a/snaps/features/custom-ui/user-defined-components.md b/snaps/features/custom-ui/user-defined-components.md index b1b6b79c7a..a96cf2f3ff 100644 --- a/snaps/features/custom-ui/user-defined-components.md +++ b/snaps/features/custom-ui/user-defined-components.md @@ -5,7 +5,7 @@ sidebar_position: 5 # User-defined components -When using [Custom UI with JSX](with-jsx.md), you can create your own components by composing +When using [Custom UI with JSX](index.md), you can create your own components by composing existing components or other user-defined components. ## Basic example diff --git a/snaps/features/custom-ui/with-jsx.md b/snaps/features/custom-ui/with-jsx.md deleted file mode 100644 index 545ab1d638..0000000000 --- a/snaps/features/custom-ui/with-jsx.md +++ /dev/null @@ -1,748 +0,0 @@ ---- -description: Display custom user interface components using JSX. -sidebar_position: 4 ---- - -# Custom UI with JSX - -You can display custom user interface (UI) JSX 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](../transaction-insights.md) -- [Signature insights](../signature-insights.md) - -:::note -JSX is supported in MetaMask Extension and Flask version 12+. New UI components will be added as JSX components. The previous function-based library is deprecated. -::: - -To use custom UI with JSX, first install [`@metamask/snaps-sdk`](https://github.com/MetaMask/snaps/tree/main/packages/snaps-sdk) -using the following command: - -```bash -yarn add @metamask/snaps-sdk -``` - -Then, whenever you're required to return a custom UI JSX 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) (the [`panel`](./index.md#panel) function equivalent) using [`snap_dialog`](../../reference/snaps-api.md#snap_dialog): - -```javascript title="index.jsx" -import { Box, Heading, Text } from "@metamask/snaps-sdk/jsx"; - -await snap.request({ - method: "snap_dialog", - params: { - type: "alert", - content: ( -
- -
- -### `Button` - -Outputs a button that the user can select. -For use in [interactive UI](interactive-ui.md). - -#### Props - -- `children`: `string` - The text of the button. -- `type` - (Optional) The type of button. - Possible values are `"button"` or `"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. -- `variant` - (Optional) Determines the appearance of the button. - Possible values are `"primary"` or `"destructive"`. - The default is `"primary"`. - -#### Example - -```javascript -import { Box, Heading, Button } from "@metamask/snaps-sdk/jsx"; - -const interfaceId = await snap.request({ - method: "snap_createInterface", - params: { - ui: ( -- -
- -### `Copyable` - -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. - -#### Example - -```javascript title="index.jsx" -import { Box, Text, Copyable } from "@metamask/snaps-sdk/jsx"; - -await snap.request({ - method: "snap_dialog", - params: { - type: "alert", - content: ( -- -
- -### `Divider` - -Outputs a horizontal divider. - -#### Example - -```javascript title="index.jsx" -import { Box, Heading, Divider, Text } from "@metamask/snaps-sdk/jsx"; - -module.exports.onHomePage = async () => { - return { - content: ( -- -
- -### `Dropdown` - -Outputs a dropdown for use in [interactive UI](interactive-ui.md). - -#### Props - -- `name`: `string` - The name sent to [`onUserInput`](../../reference/entry-points.md#onuserinput). -- `children`: `Option[]` - One or more `Option` components with the following props: - - `value`: `string` - The value sent to [`onUserInput`](../../reference/entry-points.md#onuserinput). - - `children`: `string` - The text displayed in the dropdown for that option. - -#### Example - -```js -import { Box, Text, Dropdown } from "@metamask/snaps-sdk/jsx"; - -const interfaceId = await snap.request({ - method: "snap_createInterface", - params: { - ui: ( -- -
- -### `Form` - -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. -- `children`: `array` - An array of [`Input`](#input) or [`Button`](#button) components. - -#### Example - -```js -import { Form, Input, Button } from "@metamask/snaps-sdk/jsx"; - -const interfaceId = await snap.request({ - method: "snap_createInterface", - params: { - ui: ( - - ), - }, -}); - -await snap.request({ - method: "snap_dialog", - params: { - type: "Alert", - id: interfaceId, - }, -}); -``` - -- -
- -### `Heading` - -Outputs a heading. -This is useful for [`Box`](#box) titles. - -#### Example - -```javascript title="index.jsx" -import { Box, Heading, Text } from "@metamask/snaps-sdk/jsx"; - -module.exports.onHomePage = async () => { - return { - content: ( -- -
- -### `Image` - -Outputs an image. -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. - -The SVG is rendered within an `` tag, which prevents JavaScript or interaction events from -being supported. - -:::note -To disable image support, set the [`features.images`](../../reference/cli/options.md#featuresimages) -configuration option to `false`. -The default is `true`. -::: - -#### Props - -- `src`: `string` - An inline SVG. -- `alt`: `string` - An optional alternative text for the image. - -#### Example - -```javascript title="index.jsx" -import { Box, Heading, Text, Image } from "@metamask/snaps-sdk/jsx"; -import svgIcon from "./path/to/icon.svg"; - -module.exports.onHomePage = async () => { - return { - content: ( -- -
- -:::note -See the [`@metamask/images-example-snap`](https://github.com/MetaMask/snaps/tree/main/packages/examples/packages/images) -package for a full example of implementing images. -::: - -### `Input` - -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. -- `type` - (Optional) The type of input. - Possible values are `"text"`, `"number"`, or `"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. - -#### Example - -```js -import { Form, Input, Button } from "@metamask/snaps-sdk/jsx"; - -const interfaceId = await snap.request({ - method: "snap_createInterface", - params: { - ui: ( - - ), - }, -}); - -await snap.request({ - method: "snap_dialog", - params: { - type: "Alert", - id: interfaceId, - }, -}); -``` - -- -
- -### `Italic` - -Outputs italic text. - -#### Example - -```javascript title="index.jsx" -import { Box, Heading, Text, Italic } from "@metamask/snaps-sdk/jsx"; - -await snap.request({ - method: "snap_dialog", - params: { - type: "alert", - content: ( -- -
- -### `Row` - -Outputs a row with a label and value, which can be used for key-value data. - -#### Props - -- `label`: `string` - The label of the row. -- `variant` - (Optional) The variant of the label. - Possible values are `"default"`, `"error"`, or `"warning"`. -- `children` - The value of the row, which can be a [`Text`](#text), [`Image`](#image), or - [`Address`](#address) component. - -#### Example - -```javascript title="index.jsx" -import { Box, Row, Text, Address } from "@metamask/snaps-sdk/jsx"; - -await snap.request({ - method: "snap_dialog", - params: { - type: "alert", - content: ( -- -
- -### `Spinner` - -Outputs a loading indicator. - -#### Example - -```javascript title="index.jsx" -import { Box, Heading, Spinner } from "@metamask/snaps-sdk/jsx"; - -await snap.request({ - method: "snap_dialog", - params: { - type: "alert", - content: ( -- -
- -### `Text` - -Outputs text. - -#### Example - -```javascript title="index.jsx" -import { Box, Heading, Text } from "@metamask/snaps-sdk/jsx"; - -module.exports.onHomePage = async () => { - return { - content: ( -- -
- -### Emojis - -Text-based components (such as [`Heading`](#heading) and [`Text`](#text)) accept emojis. - -#### Example - -```javascript title="index.jsx" -import { Box, Heading, Text } from "@metamask/snaps-sdk/jsx"; - -await snap.request({ - method: "snap_dialog", - params: { - type: "alert", - content: ( -- -
- -## User-defined components - -In addition to the components provided by the SDK, you can [define your own components](user-defined-components.md). diff --git a/snaps/index.mdx b/snaps/index.mdx index 843f95f089..c08e5c169b 100644 --- a/snaps/index.mdx +++ b/snaps/index.mdx @@ -36,6 +36,12 @@ The following Snaps features are available in the stable version of MetaMask: title: "Custom EVM accounts", description: "Connect to custom EVM accounts in MetaMask.", }, + { + icon: require("./assets/features/name-resolution.png").default, + href: "features/custom-name-resolution", + title: "Custom name resolution", + description: "Resolve names to addresses and vice versa.", + }, { icon: require("./assets/features/custom-ui.png").default, href: "features/custom-ui", @@ -133,13 +139,6 @@ the canary distribution of MetaMask: description: "Connect to ERC-4337 accounts in MetaMask.", flaskOnly: true, }, - { - icon: require("./assets/features/name-resolution.png").default, - href: "features/custom-name-resolution", - title: "Name resolution", - description: "Resolve names to addresses and vice versa.", - flaskOnly: true, - }, { icon: require("./assets/features/signature-insights.png").default, href: "features/signature-insights", diff --git a/snaps/reference/entry-points.md b/snaps/reference/entry-points.md index d965204d2b..dfddfa22a0 100644 --- a/snaps/reference/entry-points.md +++ b/snaps/reference/entry-points.md @@ -649,11 +649,12 @@ To respond to [interactive UI](../features/custom-ui/interactive-ui.md) events, - `id` - The ID of the interface being acted on. - `event` - An event object containing: - `type` - The type of the event. - Possible values are `ButtonClickEvent`, `FormSubmitEvent`, or `InputChangeEvent`. + Possible values are `ButtonClickEvent`, `FormSubmitEvent`, `InputChangeEvent`, and `FileInputEvent`. These enums are exported from the `@metamask/snaps-sdk` module. - `name` - The name of the component that fired the event. Optional when the event type is `ButtonClickEvent`. - `value` - When the event type is `FormSubmitEvent`, the values in the form as an object. +- `context` - The context object passed to the interface when calling [`snap_createInterface`](./snaps-api.md#snap_createinterface), or `null`. #### Example diff --git a/snaps/reference/snaps-api.md b/snaps/reference/snaps-api.md index d85837deee..270a43123e 100644 --- a/snaps/reference/snaps-api.md +++ b/snaps/reference/snaps-api.md @@ -860,6 +860,7 @@ Creates an interactive interface for use in [interactive UI](../features/custom- An object containing: - `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. #### Returns diff --git a/vercel.json b/vercel.json index 0c307a4f33..53fb82e6b7 100644 --- a/vercel.json +++ b/vercel.json @@ -402,6 +402,10 @@ "source": "/snaps/how-to/use-custom-ui/", "destination": "/snaps/features/custom-ui/" }, + { + "source": "/snaps/features/custom-ui/with-jsx/", + "destination": "/snaps/features/custom-ui/" + }, { "source": "/snaps/how-to/localize-a-snap/", "destination": "/snaps/features/localization/"