Skip to content

Commit

Permalink
Support conditional children in most JSX components (#2506)
Browse files Browse the repository at this point in the history
This adds support for conditional children in most JSX components. The
exceptions are `Field`, `Row`, and other components which don't have
children in the first place. For example, the following is now possible:

```tsx
<Box direction="horizontal" alignment="space-between">
  {condition && <Text>Hello</Text>}
</Box>
```

To support this, I've added `boolean` as valid prop for the JSX
components. The `getJsxChildren` function filters out any falsy or
literal `true` values.

I've also added a small contributing guide for conventions around JSX
components, including the support for conditional children.

Closes #2505.

---------

Co-authored-by: MetaMask Bot <[email protected]>
  • Loading branch information
Mrtenz and metamaskbot committed Jun 25, 2024
1 parent c281824 commit d738f7c
Show file tree
Hide file tree
Showing 56 changed files with 543 additions and 116 deletions.
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": "WfupwVnHUswiO0x/o2coJ0oj85v1x0j7wx1c5lYxP+o=",
"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": "+WhZ7cQ8dqA46bL5kzblh/1+GRShg87VtAS5N8N8+bU=",
"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": "cvVZ8a8g9/b3tXhh9d1zf1GU11WvqcwVnR90ilpGSGw=",
"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": "fuKiL65m1QakTuad3sCbK8YzRLNgVb9o/gSg80FK4RE=",
"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": "I8VkGGWoxhalUw5IIncvCY/InJ15yst1MTnICJ6jUZ4=",
"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": "bt0ymBAUIDJC0ksow6/BO2+TCm8l5f4I7myCg/tXJfc=",
"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": "P87ZOtKfVhN78E9zEw5fTGWhgKG0assHA1MZQNAZ0Xk=",
"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": "sNKcZWHKrpSkWmsHD9nw4SNjuYehxTTXI+PhF0PAyP4=",
"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": "y9N2+eSpLMWFxoH+gmVT9u7oR95EP8QaYnlFNowAdZE=",
"location": {
"npm": {
"filePath": "dist/bundle.js",
Expand Down
2 changes: 1 addition & 1 deletion packages/examples/packages/file-upload/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": "9m0//6LmoFrxb/Mpkjlr7eNRe9HK92iKJgtqtijlkFw=",
"shasum": "axxTRcxOlRzfmwdfTGo0MGMGxIXqxWW3ZMcvgZgU0RU=",
"location": {
"npm": {
"filePath": "dist/bundle.js",
Expand Down
2 changes: 1 addition & 1 deletion packages/examples/packages/get-entropy/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": "sKg86tSHApZz49OdruONj63Yhts7zDlyLF2lpf6sguw=",
"shasum": "+Dq7vWhymZkiKZPixpzPOac9GYNFd3NXZmThe+RP5Rk=",
"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": "YONnSNnY1QXI799OnXcq7pOJ9mB2mf0TKA+hwrXei0M=",
"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": "A9oCcxfQ/Ze21a+qSjmFEMjpyJDZTXBEUF/eEtzr00g=",
"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": "QpOZlqHNXUWxJEkcks0CEg15OO3HSximP79r+3hronM=",
"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": "hFzGG0OogA6v6B3SOokVHVqTRuuTyLdA9iULpuifFAo=",
"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": "cRsMxa73YE9a7rrLfAvqWkL7LtqDCt1KQifgF4bA/YA=",
"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": "o4UgAxX2mrxEIUbi2og85R/dECjjg+q51X0t1x8KXb4=",
"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": "3F5KdhaTzO0rYEAOJ9Y7Q0COWJqXOqcyTkG0FqdZ05s=",
"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": "NUAroyflmKAfjOcXwHF9PWN9Ioa9AbakdYBBduNtlEI=",
"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": "Hpmj/t7F9hsI52wGOdI+ak3W8yYLsQAKDrwT5tVhnYg=",
"location": {
"npm": {
"filePath": "dist/bundle.js",
Expand Down
2 changes: 1 addition & 1 deletion packages/examples/packages/localization/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": "czQq93Uay+jE8HZvwSViZfMdDQTPn0ClMJaH34VN0dc=",
"shasum": "wtOoGYeD+m/9PFLtyVgAEOLeJaZbmScyb5ovC1S4AWA=",
"location": {
"npm": {
"filePath": "dist/bundle.js",
Expand Down
2 changes: 1 addition & 1 deletion packages/examples/packages/manage-state/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": "Vr0QhrtHYgg7DFczqQc4KEkAkKrOCOAc3ZnNesEVZ+w=",
"shasum": "3CUmmQR8Rm9YPrR2vYdg97SGUzUndQf3OgYrUzlvLI4=",
"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": "VDkYGW0UgbTFLVuhnjjbYCJvHlMaFRfklmdUK3wyl4w=",
"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": "6os9tFCmhv3HTapJ6Mzr5eG04r28c+hjgD/cLSDraEY=",
"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": "rG0w/CpDp7pUUEYz6z6LB/t2UtOnLPq3tXNC0ZuI5p4=",
"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": "3sWzEjRApKpX8lrHwPjB4f0kuvwx7o1ZiuPxqTrEl3s=",
"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": "h6yDf1EBo4mpSb1qqHGQiutSvuExPmtthseHyuXhsvQ=",
"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": "VWTxqVgjWnanv5fmejkDm5Gz+yiKveFROceWqIg6vi0=",
"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": "0PQHPzqWuahbPrh5XviC7NnEnRhA185kaAIdCZcOfqs=",
"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

0 comments on commit d738f7c

Please sign in to comment.