Skip to content

Commit b29b285

Browse files
committed
add SettingCell component
1 parent 7e0e53c commit b29b285

File tree

7 files changed

+140
-3
lines changed

7 files changed

+140
-3
lines changed

packages/examples/packages/browserify-plugin/snap.manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
"url": "https://github.com/MetaMask/snaps.git"
88
},
99
"source": {
10-
"shasum": "jhSaoXggl7hhgHzX7tkJvz5Ig7tLJFl6RLLD81e1628=",
10+
"shasum": "1q/3dPvtH86iJdCbBXMiTDHoyomlRIwmvzZajrAYRBo=",
1111
"location": {
1212
"npm": {
1313
"filePath": "dist/bundle.js",

packages/examples/packages/browserify/snap.manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
"url": "https://github.com/MetaMask/snaps.git"
88
},
99
"source": {
10-
"shasum": "qlJe2g0xM6TBU8vzDMmybMmcKXq20PU0ZEhQwKcajoo=",
10+
"shasum": "YGdpnj35QH8aBahKsmbftqNwvRLjaJcZ0hxGMucVhUY=",
1111
"location": {
1212
"npm": {
1313
"filePath": "dist/bundle.js",
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { Input } from './form';
2+
import { SettingCell } from './SettingCell';
3+
4+
describe('SettingCell', () => {
5+
it('renders a setting cell', () => {
6+
const result = (
7+
<SettingCell title="Title" description="Description">
8+
<Input name="setting1" />
9+
</SettingCell>
10+
);
11+
12+
expect(result).toStrictEqual({
13+
type: 'SettingCell',
14+
key: null,
15+
props: {
16+
title: 'Title',
17+
description: 'Description',
18+
children: {
19+
type: 'Input',
20+
key: null,
21+
props: {
22+
name: 'setting1',
23+
},
24+
},
25+
},
26+
});
27+
});
28+
});
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import {
2+
createSnapComponent,
3+
type GenericSnapElement,
4+
type SnapsChildren,
5+
} from '../component';
6+
7+
/**
8+
* The props of the {@link SettingCell} component.
9+
*
10+
* @property title - The title.
11+
* @property description - The description.
12+
* @property children - The children to show within the cell.
13+
*/
14+
export type SettingCellProps = {
15+
title: string;
16+
description: string;
17+
children: SnapsChildren<GenericSnapElement>;
18+
};
19+
20+
const TYPE = 'SettingCell';
21+
22+
/**
23+
* A setting cell component which can be used to display a setting control.
24+
*
25+
* @param props - The props of the component.
26+
* @param props.title - The title.
27+
* @param props.description - The description.
28+
* @param props.children - The children to show within the cell.
29+
* @returns A setting cell element.
30+
* @example
31+
* <SettingCell title="Title" description="Description">
32+
* <Input name="setting1" />
33+
* </SettingCell>
34+
*/
35+
export const SettingCell = createSnapComponent<SettingCellProps, typeof TYPE>(
36+
TYPE,
37+
);
38+
39+
/**
40+
* A setting cell element.
41+
*
42+
* @see SettingCell
43+
*/
44+
export type SettingCellElement = ReturnType<typeof SettingCell>;

packages/snaps-sdk/src/jsx/components/index.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import type { ImageElement } from './Image';
1414
import type { LinkElement } from './Link';
1515
import type { RowElement } from './Row';
1616
import type { SectionElement } from './Section';
17+
import type { SettingCellElement } from './SettingCell';
1718
import type { SpinnerElement } from './Spinner';
1819
import type { TextElement } from './Text';
1920
import type { TooltipElement } from './Tooltip';
@@ -39,6 +40,7 @@ export * from './Tooltip';
3940
export * from './Footer';
4041
export * from './Container';
4142
export * from './Section';
43+
export * from './SettingCell';
4244

4345
/**
4446
* A built-in JSX element, which can be used in a Snap user interface.
@@ -63,4 +65,5 @@ export type JSXElement =
6365
| SectionElement
6466
| SpinnerElement
6567
| TextElement
66-
| TooltipElement;
68+
| TooltipElement
69+
| SettingCellElement;

packages/snaps-sdk/src/jsx/validation.test.tsx

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import {
3333
SelectorOption,
3434
Section,
3535
Avatar,
36+
SettingCell,
3637
} from './components';
3738
import {
3839
AddressStruct,
@@ -70,6 +71,7 @@ import {
7071
SelectorStruct,
7172
SectionStruct,
7273
AvatarStruct,
74+
SettingCellStruct,
7375
} from './validation';
7476

7577
describe('KeyStruct', () => {
@@ -1413,6 +1415,51 @@ describe('SectionStruct', () => {
14131415
});
14141416
});
14151417

1418+
describe('SettingCellStruct', () => {
1419+
it.each([
1420+
<SettingCell title="foo" description="bar">
1421+
<Input name="foo" />
1422+
</SettingCell>,
1423+
<SettingCell title="foo" description="bar">
1424+
<Box>
1425+
<Input name="foo" />
1426+
</Box>
1427+
</SettingCell>,
1428+
<SettingCell title="foo" description="bar">
1429+
<Form name="foobar">
1430+
<Input name="foo" />
1431+
</Form>
1432+
</SettingCell>,
1433+
])('validates a setting cell element', (value) => {
1434+
expect(is(value, SettingCellStruct)).toBe(true);
1435+
});
1436+
1437+
it.each([
1438+
'foo',
1439+
42,
1440+
null,
1441+
undefined,
1442+
{},
1443+
[],
1444+
// @ts-expect-error - Invalid props.
1445+
<SettingCell />,
1446+
// @ts-expect-error - Invalid props.
1447+
<SettingCell foo="bar">
1448+
<Input name="foo" />
1449+
</SettingCell>,
1450+
<Box>
1451+
<Input name="foo" />
1452+
</Box>,
1453+
<Row label="label">
1454+
<Image src="<svg />" alt="alt" />
1455+
</Row>,
1456+
// @ts-expect-error - Invalid props.
1457+
<SettingCell title="foo" description="bar"></SettingCell>,
1458+
])('does not validate "%p"', (value) => {
1459+
expect(is(value, SettingCellStruct)).toBe(false);
1460+
});
1461+
});
1462+
14161463
describe('isJSXElement', () => {
14171464
it.each([
14181465
<Text>foo</Text>,

packages/snaps-sdk/src/jsx/validation.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ import {
8484
type SelectorOptionElement,
8585
IconName,
8686
} from './components';
87+
import type { SettingCellElement } from './components/SettingCell';
8788

8889
/**
8990
* A struct for the {@link Key} type.
@@ -632,6 +633,18 @@ export const SectionStruct: Describe<SectionElement> = element('Section', {
632633
),
633634
});
634635

636+
/**
637+
* A struct for the {@link SettingCellElement} type.
638+
*/
639+
export const SettingCellStruct: Describe<SettingCellElement> = element(
640+
'SettingCell',
641+
{
642+
children: BoxChildrenStruct,
643+
title: string(),
644+
description: string(),
645+
},
646+
);
647+
635648
/**
636649
* A subset of JSX elements that are allowed as children of the Footer component.
637650
* This set should include a single button or a tuple of two buttons.
@@ -820,6 +833,7 @@ export const BoxChildStruct = typedUnion([
820833
SelectorStruct,
821834
SectionStruct,
822835
AvatarStruct,
836+
SettingCellStruct,
823837
]);
824838

825839
/**
@@ -885,6 +899,7 @@ export const JSXElementStruct: Describe<JSXElement> = typedUnion([
885899
SelectorOptionStruct,
886900
SectionStruct,
887901
AvatarStruct,
902+
SettingCellStruct,
888903
]);
889904

890905
/**

0 commit comments

Comments
 (0)