Skip to content

Commit

Permalink
Fix type issue with Field
Browse files Browse the repository at this point in the history
  • Loading branch information
GuillaumeRx committed Sep 12, 2024
1 parent 41b33ed commit 86527a8
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 16 deletions.
5 changes: 5 additions & 0 deletions packages/snaps-sdk/src/jsx/component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@ export type Nestable<Type> = Type | Nestable<Type>[];
*/
export type SnapsChildren<Type> = Nestable<Type | boolean | null>;

/**
* A type type that can be a generic JSX element, a boolean, or null.
*/
export type GenericSnapChildren = GenericSnapElement | boolean | null;

/**
* A JSX node, which can be an element, a string, null, or an array of nodes.
*/
Expand Down
20 changes: 20 additions & 0 deletions packages/snaps-sdk/src/jsx/components/form/Field.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -322,4 +322,24 @@ describe('Field', () => {
},
});
});

it('renders a field with a conditional', () => {
const result = (
<Field>
<Input name="foo" />
{false && <Button type="submit">Submit</Button>}
</Field>
);

expect(result).toStrictEqual({
type: 'Field',
key: null,
props: {
children: {
type: 'Input',
name: 'foo',
},
},
});
});
});
8 changes: 4 additions & 4 deletions packages/snaps-sdk/src/jsx/components/form/Field.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { GenericSnapElement } from '../../component';
import type { GenericSnapChildren } from '../../component';
import { createSnapComponent } from '../../component';
import type { CheckboxElement } from './Checkbox';
import type { DropdownElement } from './Dropdown';
Expand All @@ -18,9 +18,9 @@ export type FieldProps = {
label?: string | undefined;
error?: string | undefined;
children:
| [InputElement, GenericSnapElement]
| [GenericSnapElement, InputElement]
| [GenericSnapElement, InputElement, GenericSnapElement]
| [InputElement, GenericSnapChildren]
| [GenericSnapChildren, InputElement]
| [GenericSnapChildren, InputElement, GenericSnapChildren]
| DropdownElement
| RadioGroupElement
| FileInputElement
Expand Down
45 changes: 33 additions & 12 deletions packages/snaps-sdk/src/jsx/validation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,27 @@ function children<Head extends AnyStruct, Tail extends AnyStruct[]>(
>;
}

/**
* A helper function for creating a struct which allows a single child of a specific
* type, as well as `null` and `boolean`.
*
* @param struct - The struct to allow as a single child.
* @returns The struct for the children.
*/
function singleChild<Type extends AnyStruct>(
struct: Type,
): Struct<Infer<Type> | boolean | null, null> {
return nullable(
selectiveUnion((value) => {
if (typeof value === 'boolean') {
return boolean();
}

return struct;
}),
) as unknown as Struct<Infer<Type> | boolean | null, null>;
}

/**
* A helper function for creating a struct for a JSX element.
*
Expand Down Expand Up @@ -311,30 +332,30 @@ export const FileInputStruct: Describe<FileInputElement> = element(
/**
* A subset of JSX elements that represent the tuple Box + Input of the Field children.
*/
// eslint-disable-next-line @typescript-eslint/no-use-before-define
const BOX_INPUT_LEFT = [lazy(() => BoxChildStruct), InputStruct] as [
typeof BoxChildStruct,
typeof InputStruct,
];
const BOX_INPUT_LEFT = [
// eslint-disable-next-line @typescript-eslint/no-use-before-define
singleChild(lazy(() => BoxChildStruct)),
InputStruct,
] as [typeof BoxChildStruct, typeof InputStruct];

/**
* A subset of JSX elements that represent the tuple Input + Box of the Field children.
*/
// eslint-disable-next-line @typescript-eslint/no-use-before-define
const BOX_INPUT_RIGHT = [InputStruct, lazy(() => BoxChildStruct)] as [
typeof InputStruct,
typeof BoxChildStruct,
];
const BOX_INPUT_RIGHT = [
InputStruct,
// eslint-disable-next-line @typescript-eslint/no-use-before-define
singleChild(lazy(() => BoxChildStruct)),
] as [typeof InputStruct, typeof BoxChildStruct];

/**
* A subset of JSX elements that represent the tuple Box + Input + Box of the Field children.
*/
const BOX_INPUT_BOTH = [
// eslint-disable-next-line @typescript-eslint/no-use-before-define
lazy(() => BoxChildStruct),
singleChild(lazy(() => BoxChildStruct)),
InputStruct,
// eslint-disable-next-line @typescript-eslint/no-use-before-define
lazy(() => BoxChildStruct),
singleChild(lazy(() => BoxChildStruct)),
] as [typeof BoxChildStruct, typeof InputStruct, typeof BoxChildStruct];

/**
Expand Down

0 comments on commit 86527a8

Please sign in to comment.