Skip to content

Commit

Permalink
add SettingCell component
Browse files Browse the repository at this point in the history
  • Loading branch information
GuillaumeRx committed Dec 13, 2024
1 parent ea4b4e4 commit 21dac9d
Show file tree
Hide file tree
Showing 5 changed files with 138 additions and 1 deletion.
28 changes: 28 additions & 0 deletions packages/snaps-sdk/src/jsx/components/SettingCell.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { Input } from './form';
import { SettingCell } from './SettingCell';

describe('SettingCell', () => {
it('renders a setting cell', () => {
const result = (
<SettingCell title="Title" description="Description">
<Input name="setting1" />
</SettingCell>
);

expect(result).toStrictEqual({
type: 'SettingCell',
key: null,
props: {
title: 'Title',
description: 'Description',
children: {
type: 'Input',
key: null,
props: {
name: 'setting1',
},
},
},
});
});
});
44 changes: 44 additions & 0 deletions packages/snaps-sdk/src/jsx/components/SettingCell.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import {
createSnapComponent,
type GenericSnapElement,
type SnapsChildren,
} from '../component';

/**
* The props of the {@link SettingCell} component.
*
* @property title - The title.
* @property description - The description.
* @property children - The children to show within the cell.
*/
export type SettingCellProps = {
title: string;
description: string;
children: SnapsChildren<GenericSnapElement>;
};

const TYPE = 'SettingCell';

/**
* A setting cell component which can be used to display a setting control.
*
* @param props - The props of the component.
* @param props.title - The title.
* @param props.description - The description.
* @param props.children - The children to show within the cell.
* @returns A setting cell element.
* @example
* <SettingCell title="Title" description="Description">
* <Input name="setting1" />
* </SettingCell>
*/
export const SettingCell = createSnapComponent<SettingCellProps, typeof TYPE>(
TYPE,
);

/**
* A setting cell element.
*
* @see SettingCell
*/
export type SettingCellElement = ReturnType<typeof SettingCell>;
5 changes: 4 additions & 1 deletion packages/snaps-sdk/src/jsx/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import type { ImageElement } from './Image';
import type { LinkElement } from './Link';
import type { RowElement } from './Row';
import type { SectionElement } from './Section';
import type { SettingCellElement } from './SettingCell';
import type { SpinnerElement } from './Spinner';
import type { TextElement } from './Text';
import type { TooltipElement } from './Tooltip';
Expand All @@ -39,6 +40,7 @@ export * from './Tooltip';
export * from './Footer';
export * from './Container';
export * from './Section';
export * from './SettingCell';

/**
* A built-in JSX element, which can be used in a Snap user interface.
Expand All @@ -63,4 +65,5 @@ export type JSXElement =
| SectionElement
| SpinnerElement
| TextElement
| TooltipElement;
| TooltipElement
| SettingCellElement;
47 changes: 47 additions & 0 deletions packages/snaps-sdk/src/jsx/validation.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import {
SelectorOption,
Section,
Avatar,
SettingCell,
} from './components';
import {
AddressStruct,
Expand Down Expand Up @@ -70,6 +71,7 @@ import {
SelectorStruct,
SectionStruct,
AvatarStruct,
SettingCellStruct,
} from './validation';

describe('KeyStruct', () => {
Expand Down Expand Up @@ -1414,6 +1416,51 @@ describe('SectionStruct', () => {
});
});

describe('SettingCellStruct', () => {
it.each([
<SettingCell title="foo" description="bar">
<Input name="foo" />
</SettingCell>,
<SettingCell title="foo" description="bar">
<Box>
<Input name="foo" />
</Box>
</SettingCell>,
<SettingCell title="foo" description="bar">
<Form name="foobar">
<Input name="foo" />
</Form>
</SettingCell>,
])('validates a setting cell element', (value) => {
expect(is(value, SettingCellStruct)).toBe(true);
});

it.each([
'foo',
42,
null,
undefined,
{},
[],
// @ts-expect-error - Invalid props.
<SettingCell />,
// @ts-expect-error - Invalid props.
<SettingCell foo="bar">
<Input name="foo" />
</SettingCell>,
<Box>
<Input name="foo" />
</Box>,
<Row label="label">
<Image src="<svg />" alt="alt" />
</Row>,
// @ts-expect-error - Invalid props.
<SettingCell title="foo" description="bar"></SettingCell>,
])('does not validate "%p"', (value) => {
expect(is(value, SettingCellStruct)).toBe(false);
});
});

describe('isJSXElement', () => {
it.each([
<Text>foo</Text>,
Expand Down
15 changes: 15 additions & 0 deletions packages/snaps-sdk/src/jsx/validation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ import {
type SelectorOptionElement,
IconName,
} from './components';
import type { SettingCellElement } from './components/SettingCell';

/**
* A struct for the {@link Key} type.
Expand Down Expand Up @@ -633,6 +634,18 @@ export const SectionStruct: Describe<SectionElement> = element('Section', {
),
});

/**
* A struct for the {@link SettingCellElement} type.
*/
export const SettingCellStruct: Describe<SettingCellElement> = element(
'SettingCell',
{
children: BoxChildrenStruct,
title: string(),
description: string(),
},
);

/**
* A subset of JSX elements that are allowed as children of the Footer component.
* This set should include a single button or a tuple of two buttons.
Expand Down Expand Up @@ -821,6 +834,7 @@ export const BoxChildStruct = typedUnion([
SelectorStruct,
SectionStruct,
AvatarStruct,
SettingCellStruct,
]);

/**
Expand Down Expand Up @@ -886,6 +900,7 @@ export const JSXElementStruct: Describe<JSXElement> = typedUnion([
SelectorOptionStruct,
SectionStruct,
AvatarStruct,
SettingCellStruct,
]);

/**
Expand Down

0 comments on commit 21dac9d

Please sign in to comment.