diff --git a/packages/snaps-sdk/src/jsx/components/Row.ts b/packages/snaps-sdk/src/jsx/components/Row.ts index b64511150f..44dc409f24 100644 --- a/packages/snaps-sdk/src/jsx/components/Row.ts +++ b/packages/snaps-sdk/src/jsx/components/Row.ts @@ -2,6 +2,7 @@ import { createSnapComponent } from '../component'; import type { AddressElement } from './Address'; import type { ImageElement } from './Image'; import type { LinkElement } from './Link'; +import type { SkeletonElement } from './Skeleton'; import type { TextElement } from './Text'; import type { ValueElement } from './Value'; @@ -13,7 +14,8 @@ export type RowChildren = | ImageElement | TextElement | ValueElement - | LinkElement; + | LinkElement + | SkeletonElement; /** * The props of the {@link Row} component. diff --git a/packages/snaps-sdk/src/jsx/components/Skeleton.test.tsx b/packages/snaps-sdk/src/jsx/components/Skeleton.test.tsx new file mode 100644 index 0000000000..6869203534 --- /dev/null +++ b/packages/snaps-sdk/src/jsx/components/Skeleton.test.tsx @@ -0,0 +1,17 @@ +import { Skeleton } from './Skeleton'; + +describe('Skeleton', () => { + it('renders a skeleton component', () => { + const result = ; + + expect(result).toStrictEqual({ + type: 'Skeleton', + key: null, + props: { + width: 320, + height: 32, + borderRadius: 'medium', + }, + }); + }); +}); diff --git a/packages/snaps-sdk/src/jsx/components/Skeleton.ts b/packages/snaps-sdk/src/jsx/components/Skeleton.ts new file mode 100644 index 0000000000..d45e821851 --- /dev/null +++ b/packages/snaps-sdk/src/jsx/components/Skeleton.ts @@ -0,0 +1,40 @@ +import { createSnapComponent } from '../component'; + +/** + * Definition of Skeleton border radius. + */ +export type SkeletonBorderRadius = 'none' | 'medium' | 'full' | undefined; + +/** + * The props of the {@link Skeleton} component. + * + * @param width - Width of the Skeleton. + * @param width - Height of the Skeleton. + * @param borderRadius - Border radius of the Skeleton. + */ +export type SkeletonProps = { + width: number | string; + height: number | string; + borderRadius?: SkeletonBorderRadius | undefined; +}; + +const TYPE = 'Skeleton'; + +/** + * A Skeleton component, which is used to display skeleton of loading content. + * + * @param props - The props of the component. + * @param props.width - Width of the Skeleton. + * @param props.width - Height of the Skeleton. + * @param props.borderRadius - Border radius of the Skeleton. + * @example + * + */ +export const Skeleton = createSnapComponent(TYPE); + +/** + * A Skeleton element. + * + * @see Skeleton + */ +export type SkeletonElement = ReturnType; diff --git a/packages/snaps-sdk/src/jsx/components/index.ts b/packages/snaps-sdk/src/jsx/components/index.ts index d26cbcd338..132faee1f1 100644 --- a/packages/snaps-sdk/src/jsx/components/index.ts +++ b/packages/snaps-sdk/src/jsx/components/index.ts @@ -15,6 +15,7 @@ import type { ImageElement } from './Image'; import type { LinkElement } from './Link'; import type { RowElement } from './Row'; import type { SectionElement } from './Section'; +import type { SkeletonElement } from './Skeleton'; import type { SpinnerElement } from './Spinner'; import type { TextElement } from './Text'; import type { TooltipElement } from './Tooltip'; @@ -41,6 +42,7 @@ export * from './Footer'; export * from './Container'; export * from './Section'; export * from './Banner'; +export * from './Skeleton'; /** * A built-in JSX element, which can be used in a Snap user interface. @@ -66,4 +68,5 @@ export type JSXElement = | SpinnerElement | TextElement | TooltipElement - | BannerElement; + | BannerElement + | SkeletonElement; diff --git a/packages/snaps-sdk/src/jsx/validation.test.tsx b/packages/snaps-sdk/src/jsx/validation.test.tsx index c656ac598f..ac927cb01b 100644 --- a/packages/snaps-sdk/src/jsx/validation.test.tsx +++ b/packages/snaps-sdk/src/jsx/validation.test.tsx @@ -34,6 +34,7 @@ import { Section, Avatar, Banner, + Skeleton, } from './components'; import { AddressStruct, @@ -72,6 +73,7 @@ import { SectionStruct, AvatarStruct, BannerStruct, + SkeletonStruct, } from './validation'; describe('KeyStruct', () => { @@ -1618,3 +1620,35 @@ describe('BannerStruct', () => { expect(is(value, BannerStruct)).toBe(false); }); }); + +describe('SkeletonStruct', () => { + it.each([ + , + , + , + , + , + , + ])(`validates a Skeleton element`, (value) => { + expect(is(value, SkeletonStruct)).toBe(true); + }); + + it.each([ + 'foo', + 42, + null, + undefined, + {}, + [], + // @ts-expect-error - Invalid props. + , + // @ts-expect-error - Invalid props. + foo, + // @ts-expect-error - Invalid props. + } severity="info"> + foo + , + ])('does not validate "%p"', (value) => { + expect(is(value, SkeletonStruct)).toBe(false); + }); +}); diff --git a/packages/snaps-sdk/src/jsx/validation.ts b/packages/snaps-sdk/src/jsx/validation.ts index 5b6c03a5e1..a6366da1c9 100644 --- a/packages/snaps-sdk/src/jsx/validation.ts +++ b/packages/snaps-sdk/src/jsx/validation.ts @@ -48,7 +48,7 @@ import type { SnapsChildren, StringElement, } from './component'; -import type { AvatarElement } from './components'; +import type { AvatarElement, SkeletonElement } from './components'; import { type AddressElement, type BoldElement, @@ -807,6 +807,17 @@ export const BannerStruct: Describe = element('Banner', { ]), }); +/** + * A struct for the {@link SkeletonElement} type. + */ +export const SkeletonStruct: Describe = element('Skeleton', { + width: union([number(), string()]), + height: union([number(), string()]), + borderRadius: optional( + nullUnion([literal('none'), literal('medium'), literal('full')]), + ), +}); + /** * A struct for the {@link RowElement} type. */ @@ -818,6 +829,7 @@ export const RowStruct: Describe = element('Row', { TextStruct, ValueStruct, LinkStruct, + SkeletonStruct, ]), variant: optional( nullUnion([literal('default'), literal('warning'), literal('critical')]), @@ -863,6 +875,7 @@ export const BoxChildStruct = typedUnion([ SectionStruct, AvatarStruct, BannerStruct, + SkeletonStruct, ]); /** @@ -932,6 +945,7 @@ export const JSXElementStruct: Describe = typedUnion([ SectionStruct, AvatarStruct, BannerStruct, + SkeletonStruct, ]); /**