diff --git a/.changeset/add-container-block.md b/.changeset/add-container-block.md new file mode 100644 index 000000000..74019037d --- /dev/null +++ b/.changeset/add-container-block.md @@ -0,0 +1,5 @@ +--- +"@slack/types": minor +--- + +feat(types): add `ContainerBlock` interface and `ContainerBlockChildBlock` union type diff --git a/packages/types/src/block-kit/blocks.ts b/packages/types/src/block-kit/blocks.ts index 365492d93..813e743f3 100644 --- a/packages/types/src/block-kit/blocks.ts +++ b/packages/types/src/block-kit/blocks.ts @@ -58,6 +58,7 @@ export type KnownBlock = | AlertBlock | CardBlock | CarouselBlock + | ContainerBlock | ContextBlock | ContextActionsBlock | DividerBlock @@ -184,6 +185,69 @@ export interface CarouselBlock extends Block { elements: CardBlock[]; } +/** + * @description A general-purpose wrapper for grouping child blocks together, with a configurable size. + * Note: `has_header_divider` cannot be set to `true` when `is_collapsible` is `true`. + * @see {@link https://docs.slack.dev/reference/block-kit/blocks/container-block Container block reference}. + */ +export interface ContainerBlock extends Block { + /** + * @description The type of block. For a container block, `type` is always `container`. + */ + type: 'container'; + /** + * @description Plain text title for the container. Maximum length is 150 characters. + * One of `title` or `rich_text_title` is required. + */ + title?: PlainTextElement; + /** + * @description Rich text title for the container. Takes precedence over `title` if both are provided. + * One of `title` or `rich_text_title` is required. + */ + rich_text_title?: RichTextBlock; + /** + * @description Subtitle for the container in plain text or mrkdwn format. Maximum length is 150 characters. + */ + subtitle?: TextObject; + /** + * @description An array of child blocks. Maximum 10 blocks. + */ + child_blocks: ( + | ActionsBlock + | ContextBlock + | DividerBlock + | FileBlock + | HeaderBlock + | ImageBlock + | InputBlock + | RichTextBlock + | SectionBlock + | TableBlock + | VideoBlock + )[]; + /** + * @description Controls the width of the container. Defaults to `"standard"`. + */ + width?: 'narrow' | 'standard' | 'wide' | 'full'; + /** + * @description An image element displayed alongside the title and subtitle. + */ + icon?: ImageElement; + /** + * @description Whether the container can be collapsed. Defaults to `false`. + */ + is_collapsible?: boolean; + /** + * @description Whether the container is collapsed by default. Requires `is_collapsible` to be `true`. Defaults to `false`. + */ + default_collapsed?: boolean; + /** + * @description Whether to show a visible border separating header from content. + * Only applies when `is_collapsible` is not `true`. Defaults to `false`. + */ + has_header_divider?: boolean; +} + /** * A helper union type of all Block Elements that can be used in a {@link ContextBlock}. * @see {@link https://docs.slack.dev/reference/block-kit/blocks/context-block Context block reference}. diff --git a/packages/types/test/blocks.test-d.ts b/packages/types/test/blocks.test-d.ts index e154b6c1b..3169703e5 100644 --- a/packages/types/test/blocks.test-d.ts +++ b/packages/types/test/blocks.test-d.ts @@ -1,5 +1,5 @@ import { expectAssignable, expectError } from 'tsd'; -import type { AlertBlock, CardBlock, CarouselBlock, KnownBlock } from '../src/index'; +import type { AlertBlock, CardBlock, CarouselBlock, ContainerBlock, KnownBlock } from '../src/index'; // CardBlock // -- sad path @@ -62,3 +62,43 @@ expectAssignable({ type: 'carousel', elements: [{ type: 'card' }], }); + +// ContainerBlock +// -- sad path +expectError({}); // missing type and child_blocks +expectError({ type: 'container' }); // missing required child_blocks +// -- happy path +expectAssignable({ + type: 'container', + title: { type: 'plain_text', text: 'My Container' }, + child_blocks: [{ type: 'divider' }], +}); +expectAssignable({ + type: 'container', + title: { type: 'plain_text', text: 'Full Container' }, + subtitle: { type: 'plain_text', text: 'A subtitle' }, + child_blocks: [{ type: 'section', text: { type: 'mrkdwn', text: 'Content' } }, { type: 'divider' }], + width: 'wide', + icon: { type: 'image', image_url: 'https://example.com/icon.png', alt_text: 'icon' }, + is_collapsible: true, + default_collapsed: true, +}); +expectAssignable({ + type: 'container', + rich_text_title: { + type: 'rich_text', + elements: [{ type: 'rich_text_section', elements: [{ type: 'text', text: 'Rich Title' }] }], + }, + child_blocks: [{ type: 'divider' }], +}); +expectAssignable({ + type: 'container', + title: { type: 'plain_text', text: 'Divider' }, + child_blocks: [{ type: 'divider' }], + has_header_divider: true, +}); +expectAssignable({ + type: 'container', + title: { type: 'plain_text', text: 'Known' }, + child_blocks: [{ type: 'divider' }], +});