Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support conditional children in most JSX components #2506

Merged
merged 10 commits into from
Jun 25, 2024
2 changes: 1 addition & 1 deletion packages/examples/packages/bip32/snap.manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"url": "https://github.com/MetaMask/snaps.git"
},
"source": {
"shasum": "7AJkQic0kErNfOuBozGOUaJ5U5Z24yOV28zHL+WEPz0=",
"shasum": "okOtnPSp63QzvGqnfiFeIj9upF+l2GUcuX0hld/8zS4=",
"location": {
"npm": {
"filePath": "dist/bundle.js",
Expand Down
2 changes: 1 addition & 1 deletion packages/examples/packages/bip44/snap.manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"url": "https://github.com/MetaMask/snaps.git"
},
"source": {
"shasum": "R/jtwKJg/6gTCuMrphuKHZkTtUlggfwnNgKiOXx11GU=",
"shasum": "9Wtu1MGgCNlXREDrOX5nYcUe+E8jESmmCEveUBR8n/c=",
"location": {
"npm": {
"filePath": "dist/bundle.js",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"url": "https://github.com/MetaMask/snaps.git"
},
"source": {
"shasum": "u7x/swxx6XHT7G0BDY8mJkwcY/mP/i4YmdYaRQ/QKZY=",
"shasum": "U3DkPSJLzf4OO7/Ybma4bBYP0fp+QpwrQXjHHyyVrW4=",
"location": {
"npm": {
"filePath": "dist/bundle.js",
Expand Down
2 changes: 1 addition & 1 deletion packages/examples/packages/browserify/snap.manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"url": "https://github.com/MetaMask/snaps.git"
},
"source": {
"shasum": "105XsceecyaQZ+reC6ZNusiOJVUMBoNSYK4PHvREPQw=",
"shasum": "O0+BkKmGK6BN1eYbct7KQEnvW3CRks/YrNUPzG79qlE=",
"location": {
"npm": {
"filePath": "dist/bundle.js",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"url": "https://github.com/MetaMask/snaps.git"
},
"source": {
"shasum": "9Ttl+TbR7gufQzhQx4o/keKeINCjio65rjLWOlP36NM=",
"shasum": "f8zeIa09pXt1W8vKHjDjznEdSjC2OBn3QVIijtHUwPg=",
"location": {
"npm": {
"filePath": "dist/bundle.js",
Expand Down
2 changes: 1 addition & 1 deletion packages/examples/packages/cronjobs/snap.manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"url": "https://github.com/MetaMask/snaps.git"
},
"source": {
"shasum": "0NNqpKgq/+zNokLs67+6vrA+kZxvDnDe9PWrX6X8Goc=",
"shasum": "v4TY+hN5aUAIdvb31+YEvWCR/Dhc5eSoqv4QZAjgE6w=",
"location": {
"npm": {
"filePath": "dist/bundle.js",
Expand Down
2 changes: 1 addition & 1 deletion packages/examples/packages/dialogs/snap.manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"url": "https://github.com/MetaMask/snaps.git"
},
"source": {
"shasum": "tDbsxyvQUz2VoKmIzIXbLr3mtJfNewiHzoEjW7X6c8k=",
"shasum": "OSa/uP5sUDFb9cgnyJF43CHugmssYIbVYFJGXutEOJ8=",
"location": {
"npm": {
"filePath": "dist/bundle.js",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"url": "https://github.com/MetaMask/snaps.git"
},
"source": {
"shasum": "8/P91GreWpqGOWLGAntmd3Kyu6A3WMelRIWUuxKcsGI=",
"shasum": "UIm8NaJ2HQ+b0/gwzMrUolBPH94WaX0krT2j2vqS8Sw=",
"location": {
"npm": {
"filePath": "dist/bundle.js",
Expand Down
2 changes: 1 addition & 1 deletion packages/examples/packages/ethers-js/snap.manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"url": "https://github.com/MetaMask/snaps.git"
},
"source": {
"shasum": "1bLwZCxQusG/VCAswAJ5ohHF6fBgiQtTLhQG1Mby4HI=",
"shasum": "2hc5tU0+vTc55vOTJm8pDwaZJBGCCrzwrkSY/ob/C/w=",
"location": {
"npm": {
"filePath": "dist/bundle.js",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"url": "https://github.com/MetaMask/snaps.git"
},
"source": {
"shasum": "9m0//6LmoFrxb/Mpkjlr7eNRe9HK92iKJgtqtijlkFw=",
"shasum": "+uPTb3bOlEydaXXUp1YaaCuR77bs/KYlnnsDrc983DY=",
"location": {
"npm": {
"filePath": "dist/bundle.js",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"url": "https://github.com/MetaMask/snaps.git"
},
"source": {
"shasum": "sKg86tSHApZz49OdruONj63Yhts7zDlyLF2lpf6sguw=",
"shasum": "9dG5S/QzV8DC7DQ10d4pp65QYKhGdsSYpUVQXM5qBN0=",
"location": {
"npm": {
"filePath": "dist/bundle.js",
Expand Down
2 changes: 1 addition & 1 deletion packages/examples/packages/get-file/snap.manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"url": "https://github.com/MetaMask/snaps.git"
},
"source": {
"shasum": "0vuiA3xbMMPYDMcE7ytDmXM0B4wwc+b90Ncy114JU24=",
"shasum": "bLUkDZXvhV/kAyeqPFVp3Bd0SPk42AVkVtfWTWKoBd4=",
"location": {
"npm": {
"filePath": "dist/bundle.js",
Expand Down
2 changes: 1 addition & 1 deletion packages/examples/packages/home-page/snap.manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"url": "https://github.com/MetaMask/snaps.git"
},
"source": {
"shasum": "I2MgHF7MuMKoGGKMSJTB2TAdRNt3ThuAs7N5QLqsFwc=",
"shasum": "6Q2MkQCJd9UneQoCp3vxQGGQ8Ajrsf86BTiPBR4CIlk=",
"location": {
"npm": {
"filePath": "dist/bundle.js",
Expand Down
2 changes: 1 addition & 1 deletion packages/examples/packages/images/snap.manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"url": "https://github.com/MetaMask/snaps.git"
},
"source": {
"shasum": "F+ZTNm0I7LeuhiRfFLz34sEn1nQrHEmZ4vbl4V1buiU=",
"shasum": "b6z/vd9UzvmbWax8XEqdu1Da6c0U8nx2fW8O3e3OVhU=",
"location": {
"npm": {
"filePath": "dist/bundle.js",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"url": "https://github.com/MetaMask/snaps.git"
},
"source": {
"shasum": "LSk+GmGMP8byzHX013+Fnj8hPWxFD1ctKE7FwmXwUZ4=",
"shasum": "V/YxuQSq7yqlK2h/zypPPaEWeloh0J9tVMjPGYm0Mgo=",
"location": {
"npm": {
"filePath": "dist/bundle.js",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"url": "https://github.com/MetaMask/snaps.git"
},
"source": {
"shasum": "gRoujvXbGzclQmIEgWQQvuKxeeTXt4jt8Kv+SggT5I8=",
"shasum": "5+rhF05TzrBN+IAV/3tL2OElXjDV3JTMpRA6ZicthAs=",
"location": {
"npm": {
"filePath": "dist/bundle.js",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"url": "https://github.com/MetaMask/snaps.git"
},
"source": {
"shasum": "pgKvkVBqtJ4sPb6shDMNXiDc1C8apmV4+WfN6ciavKg=",
"shasum": "z7xE1BJuNCfznRO3/1C3Et1FT/oKATYB3nrchlIIjTk=",
"location": {
"npm": {
"filePath": "dist/bundle.js",
Expand Down
2 changes: 1 addition & 1 deletion packages/examples/packages/json-rpc/snap.manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"url": "https://github.com/MetaMask/snaps.git"
},
"source": {
"shasum": "MDjrpUYVTAW1NxWp544Gn4DcF0t6GoDBQIR3F+zeqtI=",
"shasum": "P6W+9HEzJ6H0XuZX6lERuskbzYdOATjxbW+NjcjUmPA=",
"location": {
"npm": {
"filePath": "dist/bundle.js",
Expand Down
2 changes: 1 addition & 1 deletion packages/examples/packages/jsx/snap.manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"url": "https://github.com/MetaMask/snaps.git"
},
"source": {
"shasum": "G9fNyPGqUsjlqzMskFKEkdy04ny6eZDBBlXSajmQcN8=",
"shasum": "g1h6l5PmU3C2tXZyfdsXRmcxGWR7rmfsVLw45t3eEtg=",
"location": {
"npm": {
"filePath": "dist/bundle.js",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"url": "https://github.com/MetaMask/snaps.git"
},
"source": {
"shasum": "1Vo2b7dgicVZYWx6DMTlnkDnK6UBbk4fmilSsLKwSDg=",
"shasum": "o89z7gAMsuZ88FMA2m+7LjmH0ZXStQ4VV5joHlza15A=",
"location": {
"npm": {
"filePath": "dist/bundle.js",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"url": "https://github.com/MetaMask/snaps.git"
},
"source": {
"shasum": "czQq93Uay+jE8HZvwSViZfMdDQTPn0ClMJaH34VN0dc=",
"shasum": "O0whqPrZ7Iqr4RGBdWIi7nMcXPa/X08whUVOLT9V/ws=",
"location": {
"npm": {
"filePath": "dist/bundle.js",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"url": "https://github.com/MetaMask/snaps.git"
},
"source": {
"shasum": "Vr0QhrtHYgg7DFczqQc4KEkAkKrOCOAc3ZnNesEVZ+w=",
"shasum": "UxIvaI4TmlafrguqYUWmJ/L8iz57LSgLBBkYmqzOhaI=",
"location": {
"npm": {
"filePath": "dist/bundle.js",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"url": "https://github.com/MetaMask/snaps.git"
},
"source": {
"shasum": "6btrG6bcFAWosjSF/ldUuTd3sXNlYxVsRm0gcTJRE2M=",
"shasum": "9qUDCBIHh+FgaJSYylelB3JB1VcPmgNBESZZGNKK3/4=",
"location": {
"npm": {
"filePath": "dist/bundle.js",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"url": "https://github.com/MetaMask/snaps.git"
},
"source": {
"shasum": "khCrwAziXNhRJrV8cHp3hfRyudXVBYVB3Cew7YpWDG0=",
"shasum": "vfs20ja+DvBv5vZukhW2Y38sJY1CL3zEA14JS7725Ao=",
"location": {
"npm": {
"filePath": "dist/bundle.js",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"url": "https://github.com/MetaMask/snaps.git"
},
"source": {
"shasum": "7wOe/70O/A4BoUF5+CabV0Rjivnnv2D/xcQ1AlAZdw0=",
"shasum": "Gmn3gYzZm188ctTJgWVvvXsBCMnqKgy5MvmwHQEYowM=",
"location": {
"npm": {
"filePath": "dist/bundle.js",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"url": "https://github.com/MetaMask/snaps.git"
},
"source": {
"shasum": "5dDSK6C4XDIT1ukZh1nEimci2a+z0hnqUNEqi7qBNAk=",
"shasum": "Qj1+BivQzIMmikoDbUznJQJoEW/8BTaQaseCOcON+Zw=",
"location": {
"npm": {
"filePath": "dist/bundle.js",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"url": "https://github.com/MetaMask/snaps.git"
},
"source": {
"shasum": "8kKJRiaM18IxSr89svPvmzGIjRszgJvmfLkJxJLyFA4=",
"shasum": "9kalAse/bhDXFV4vXXNSlNZt/jxm1KkGkC1DF2nDcW8=",
"location": {
"npm": {
"filePath": "dist/bundle.js",
Expand Down
2 changes: 1 addition & 1 deletion packages/examples/packages/wasm/snap.manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"url": "https://github.com/MetaMask/snaps.git"
},
"source": {
"shasum": "DGgaRZmS8KSVnUzCq/V7f9TauAelSCFe9sg3myXrWks=",
"shasum": "fNPOi4FAZa4IXTEj/gZyBBx93NmiFlv2wGABRXK+3TY=",
"location": {
"npm": {
"filePath": "dist/bundle.js",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"url": "https://github.com/MetaMask/snaps.git"
},
"source": {
"shasum": "U4Zhw9ZpNVXJHoYfuYJ4a6j/ynAaFXxZYUYo0DSESVs=",
"shasum": "A5g5mxLzrae+3ShTHi1QDLdeHRDuUt4dGjwC2Mq/1NE=",
"location": {
"npm": {
"filePath": "dist/bundle.js",
Expand Down
8 changes: 6 additions & 2 deletions packages/snaps-jest/src/matchers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,11 @@ import type {
ComponentOrElement,
Component,
} from '@metamask/snaps-sdk';
import type { JSXElement, SnapNode } from '@metamask/snaps-sdk/jsx';
import type {
GenericSnapElement,
JSXElement,
SnapNode,
} from '@metamask/snaps-sdk/jsx';
import { isJSXElementUnsafe } from '@metamask/snaps-sdk/jsx';
import { getJsxElementFromComponent } from '@metamask/snaps-utils';
import type { Json } from '@metamask/utils';
Expand Down Expand Up @@ -234,7 +238,7 @@ export function serialiseJsx(node: SnapNode, indentation = 0): string {
return '';
}

const { type, props } = node;
const { type, props } = node as GenericSnapElement;
const trailingNewline = indentation > 0 ? '\n' : '';

if (hasProperty(props, 'children')) {
Expand Down
97 changes: 97 additions & 0 deletions packages/snaps-sdk/CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
# Contributing

## Adding new JSX components

The MetaMask Snaps SDK uses JSX components for building user interfaces in
Snaps. To add a new component, follow these steps:

1. Create a new file in the `src/jsx/components` directory, optionally in a
subdirectory if the component is part of a group of related components.
2. It is recommended to copy an existing component file and modify it to create
the new component.
3. Create a test for the new component, following the existing test files for
the other components.
4. Add the new component to the `src/jsx/components/index.ts` file, exporting it
from the file.
- This file also contains a `JSXElement` union type that should
be updated to include the new component.
5. Add validation for the component to `src/jsx/validation.ts`, making sure to
use the `Describe` helper type to ensure that the component is correctly
validated.
- Make sure to add tests for the validation in `src/jsx/validation.test.ts`
as well.
6. If the component is stateful, make sure to add it to the
`SnapInterfaceController` too.
- You can use [this PR](https://github.com/MetaMask/snaps/pull/2501) as a
reference.

### Component props

When adding a new component, make sure to document the props that the component
accepts. This can be done by adding a JSDoc comment to the component function
declaration, like so:

```typescript
/**
* The props of the {@link Dropdown} component.
*
* @property name - The name of the dropdown. This is used to identify the
* state in the form data.
* @property value - The selected value of the dropdown.
* @property children - The children of the dropdown.
*/
export type DropdownProps = {
name: string;
value?: string | undefined;
children: SnapsChildren<OptionElement>;
};
```

The props type should be exported from the component file and used in the
component function declaration, like so:

```typescript
// ...
export const Dropdown = createSnapComponent<DropdownProps, typeof TYPE>(TYPE);
```

To ensure consistency, make sure to follow the existing patterns in the codebase
when documenting component props.

#### Optional props

Optional props should be both marked with a `?` in the type definition, and
also include `undefined` in the type definition. This is to ensure that the
component can be used with or without TypeScript's exact optional props feature.

```typescript
export type ComponentProps = {
value?: string | undefined;
};
```

#### Children

In most cases, the children prop should be defined as `SnapsChildren` to allow
for both a single child element or an array of child elements. There are some
exceptions to this rule, such as when the component only accepts a single child
element (e.g., `Field`).

Children should also accept `boolean` and `null` values to allow for conditional
rendering of child elements. This is handled automatically by the
`SnapsChildren` type.

```typescript
export type ComponentProps = {
children: SnapsChildren<string>; // Nestable<string | boolean | null>;
};
```

If the children are optional, make sure to include `undefined` in the type and
add the `?` to the prop definition.

```typescript
export type ComponentProps = {
children?: SnapsChildren<string> | undefined;
};
```
6 changes: 5 additions & 1 deletion packages/snaps-sdk/jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@ const { resolve } = require('path');
const baseConfig = require('../../jest.config.base');

module.exports = deepmerge(baseConfig, {
collectCoverageFrom: ['!./src/**/index.ts'],
collectCoverageFrom: [
'!./src/**/index.ts',
'!./src/types/global.ts',
'!./src/types/images.ts',
],

coverageThreshold: {
global: {
Expand Down
Loading
Loading