diff --git a/packages/examples/packages/browserify-plugin/snap.manifest.json b/packages/examples/packages/browserify-plugin/snap.manifest.json
index fed1f39649..741d09c663 100644
--- a/packages/examples/packages/browserify-plugin/snap.manifest.json
+++ b/packages/examples/packages/browserify-plugin/snap.manifest.json
@@ -7,7 +7,7 @@
"url": "https://github.com/MetaMask/snaps.git"
},
"source": {
- "shasum": "4yLB19XYAdGgHBPFlVOzCkb/JUZCjSajPRSQWs+a3uE=",
+ "shasum": "d1js9Y4zJwk7n/e47V5fdMreo1FBtVKl4GtPhfckZrs=",
"location": {
"npm": {
"filePath": "dist/bundle.js",
diff --git a/packages/examples/packages/browserify/snap.manifest.json b/packages/examples/packages/browserify/snap.manifest.json
index c650c852f4..5a4f36c49a 100644
--- a/packages/examples/packages/browserify/snap.manifest.json
+++ b/packages/examples/packages/browserify/snap.manifest.json
@@ -7,7 +7,7 @@
"url": "https://github.com/MetaMask/snaps.git"
},
"source": {
- "shasum": "+0hxp1uhfCqe9KR+4RPDSPGHFTgRyGULKLn9XWwCmsY=",
+ "shasum": "VvMm+Zet1+q467UNweIuLLtYVoHoJdTeNjZn0xnEwO8=",
"location": {
"npm": {
"filePath": "dist/bundle.js",
diff --git a/packages/snaps-controllers/src/interface/utils.test.tsx b/packages/snaps-controllers/src/interface/utils.test.tsx
index 10403584d5..c00f9de819 100644
--- a/packages/snaps-controllers/src/interface/utils.test.tsx
+++ b/packages/snaps-controllers/src/interface/utils.test.tsx
@@ -242,6 +242,21 @@ describe('constructState', () => {
});
});
+ it('handles root level Field', () => {
+ const element = (
+
+
+
+
+
+ );
+
+ const result = constructState({}, element);
+ expect(result).toStrictEqual({
+ foo: 'bar',
+ });
+ });
+
it('handles root level inputs with value', () => {
const element = (
diff --git a/packages/snaps-rpc-methods/src/permitted/createInterface.test.tsx b/packages/snaps-rpc-methods/src/permitted/createInterface.test.tsx
index 4550ec9a02..15e530e3a1 100644
--- a/packages/snaps-rpc-methods/src/permitted/createInterface.test.tsx
+++ b/packages/snaps-rpc-methods/src/permitted/createInterface.test.tsx
@@ -9,6 +9,7 @@ import {
Form,
Container,
Footer,
+ Copyable,
} from '@metamask/snaps-sdk/jsx';
import type { JsonRpcRequest, PendingJsonRpcResponse } from '@metamask/utils';
@@ -140,7 +141,7 @@ describe('snap_createInterface', () => {
error: {
code: -32602,
message:
- 'Invalid params: At path: ui -- Expected type to be one of: "Address", "Bold", "Box", "Button", "Copyable", "Divider", "Dropdown", "RadioGroup", "FileInput", "Form", "Heading", "Input", "Image", "Italic", "Link", "Row", "Spinner", "Text", "Tooltip", "Checkbox", "Card", "Icon", "Selector", "Section", "Avatar", "Container", but received: undefined.',
+ 'Invalid params: At path: ui -- Expected type to be one of: "Address", "Bold", "Box", "Button", "Copyable", "Divider", "Dropdown", "RadioGroup", "Field", "FileInput", "Form", "Heading", "Input", "Image", "Italic", "Link", "Row", "Spinner", "Text", "Tooltip", "Checkbox", "Card", "Icon", "Selector", "Section", "Avatar", "Container", but received: undefined.',
stack: expect.any(String),
},
id: 1,
@@ -179,7 +180,7 @@ describe('snap_createInterface', () => {
ui: (
-
+
) as JSXElement,
@@ -190,7 +191,7 @@ describe('snap_createInterface', () => {
error: {
code: -32602,
message:
- 'Invalid params: At path: ui.props.children -- Expected type to be one of: "Address", "Bold", "Box", "Button", "Copyable", "Divider", "Dropdown", "RadioGroup", "FileInput", "Form", "Heading", "Input", "Image", "Italic", "Link", "Row", "Spinner", "Text", "Tooltip", "Checkbox", "Card", "Icon", "Selector", "Section", "Avatar", but received: "Field".',
+ 'Invalid params: At path: ui.props.children.props.children -- Expected the value to satisfy a union of `tuple | tuple | tuple | object | object | object | object | object | object`, but received: [object Object].',
stack: expect.any(String),
},
id: 1,
diff --git a/packages/snaps-sdk/src/jsx/components/form/Field.ts b/packages/snaps-sdk/src/jsx/components/form/Field.ts
index 067ab525f8..0493311842 100644
--- a/packages/snaps-sdk/src/jsx/components/form/Field.ts
+++ b/packages/snaps-sdk/src/jsx/components/form/Field.ts
@@ -32,8 +32,7 @@ export type FieldProps = {
const TYPE = 'Field';
/**
- * A field component, which is used to create a form field. This component can
- * only be used as a child of the {@link Form} component.
+ * A field component, which is used to create a form field.
*
* @param props - The props of the component.
* @param props.label - The label of the field.
diff --git a/packages/snaps-sdk/src/jsx/validation.test.tsx b/packages/snaps-sdk/src/jsx/validation.test.tsx
index 234c6f6b64..a341804f72 100644
--- a/packages/snaps-sdk/src/jsx/validation.test.tsx
+++ b/packages/snaps-sdk/src/jsx/validation.test.tsx
@@ -567,6 +567,11 @@ describe('BoxStruct', () => {
foo
bar
,
+
+
+
+
+ ,
foo
@@ -620,11 +625,6 @@ describe('BoxStruct', () => {
,
-
-
-
-
- ,
,
diff --git a/packages/snaps-sdk/src/jsx/validation.ts b/packages/snaps-sdk/src/jsx/validation.ts
index 3891bc6aeb..2e11dd7435 100644
--- a/packages/snaps-sdk/src/jsx/validation.ts
+++ b/packages/snaps-sdk/src/jsx/validation.ts
@@ -507,22 +507,6 @@ export const FieldStruct: Describe = element('Field', {
children: FieldChildStruct,
});
-/**
- * A subset of JSX elements that are allowed as children of the Form component.
- */
-export const FormChildStruct = children(
- // eslint-disable-next-line @typescript-eslint/no-use-before-define
- [FieldStruct, lazy(() => BoxChildStruct)],
-) as unknown as Struct, null>;
-
-/**
- * A struct for the {@link FormElement} type.
- */
-export const FormStruct: Describe = element('Form', {
- children: FormChildStruct,
- name: string(),
-});
-
/**
* A struct for the {@link BoldElement} type.
*/
@@ -584,6 +568,19 @@ export const BoxStruct: Describe = element('Box', {
center: optional(boolean()),
});
+/**
+ * A subset of JSX elements that are allowed as children of the Form component.
+ */
+export const FormChildStruct = BoxChildrenStruct;
+
+/**
+ * A struct for the {@link FormElement} type.
+ */
+export const FormStruct: Describe = element('Form', {
+ children: FormChildStruct,
+ name: string(),
+});
+
const FooterButtonStruct = refine(ButtonStruct, 'FooterButton', (value) => {
if (
typeof value.props.children === 'string' ||
@@ -796,6 +793,7 @@ export const BoxChildStruct = typedUnion([
DividerStruct,
DropdownStruct,
RadioGroupStruct,
+ FieldStruct,
FileInputStruct,
FormStruct,
HeadingStruct,
diff --git a/packages/snaps-simulator/src/features/builder/utils.test.ts b/packages/snaps-simulator/src/features/builder/utils.test.ts
index ca124f81be..da309a21bb 100644
--- a/packages/snaps-simulator/src/features/builder/utils.test.ts
+++ b/packages/snaps-simulator/src/features/builder/utils.test.ts
@@ -9,6 +9,7 @@ import {
Copyable,
Heading,
Option,
+ Container,
} from '@metamask/snaps-sdk/jsx';
import type { NodeModel } from '@minoru/react-dnd-treeview';
@@ -30,7 +31,7 @@ describe('isValidBoxChild', () => {
});
it('returns false for invalid box children', () => {
- const child = Field({ children: Input({ name: 'input' }) });
+ const child = Container({ children: Input({ name: 'input' }) });
expect(isValidBoxChild(child)).toBe(false);
});
});
@@ -80,7 +81,7 @@ describe('setElementChildren', () => {
const element = Box({
children: [Text({ children: 'foo' }), Heading({ children: 'baz' })],
});
- const children = Field({ children: Input({ name: 'input' }) });
+ const children = Container({ children: Input({ name: 'input' }) });
const result = setElementChildren(element, children, isValidBoxChild);
expect(result).toStrictEqual(element.props.children);