Skip to content

Commit 4f03ee8

Browse files
authored
feat(types): add Card, Carousel, and Alert block types (slackapi#2567)
1 parent a5a2954 commit 4f03ee8

3 files changed

Lines changed: 146 additions & 0 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@slack/types": minor
3+
---
4+
5+
feat(types): add Card, Carousel, and Alert block types

packages/types/src/block-kit/blocks.ts

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import type {
2626
WorkflowButton,
2727
} from './block-elements';
2828
import type {
29+
MrkdwnElement,
2930
PlainTextElement,
3031
RawTextElement,
3132
SlackFileImageObject,
@@ -54,6 +55,9 @@ export interface Block {
5455
*/
5556
export type KnownBlock =
5657
| ActionsBlock
58+
| AlertBlock
59+
| CardBlock
60+
| CarouselBlock
5761
| ContextBlock
5862
| ContextActionsBlock
5963
| DividerBlock
@@ -108,6 +112,79 @@ export interface ActionsBlock extends Block {
108112
elements: ActionsBlockElement[]; // TODO: breaking change: min 1 item
109113
}
110114

115+
/**
116+
* @description A prominent notice block for displaying warnings, status updates, or other important information.
117+
* @see {@link https://docs.slack.dev/reference/block-kit/blocks/alert-block Alert block reference}.
118+
*/
119+
export interface AlertBlock extends Block {
120+
/**
121+
* @description The type of block. For an alert block, `type` is always `alert`.
122+
*/
123+
type: 'alert';
124+
/**
125+
* @description The alert message content in the form of a {@link TextObject}.
126+
*/
127+
text: TextObject;
128+
/**
129+
* @description The severity level of the alert. Defaults to `"default"` if omitted.
130+
*/
131+
level?: 'default' | 'info' | 'warning' | 'error' | 'success';
132+
}
133+
134+
/**
135+
* @description A rich display block for presenting structured content such as recommendations, results, or work items.
136+
* At least one of `hero_image`, `title`, `actions`, or `body` must be provided.
137+
* @see {@link https://docs.slack.dev/reference/block-kit/blocks/card-block Card block reference}.
138+
*/
139+
export interface CardBlock extends Block {
140+
/**
141+
* @description The type of block. For a card block, `type` is always `card`.
142+
*/
143+
type: 'card';
144+
/**
145+
* @description A top banner image for the card in the form of an {@link ImageElement}.
146+
*/
147+
hero_image?: ImageElement;
148+
/**
149+
* @description A small icon displayed next to the title and subtitle in the form of an {@link ImageElement}.
150+
*/
151+
icon?: ImageElement;
152+
/**
153+
* @description The title of the card in the form of a {@link MrkdwnElement}.
154+
* Maximum length for the text in this field is 150 characters.
155+
*/
156+
title?: MrkdwnElement;
157+
/**
158+
* @description The subtitle of the card in the form of a {@link MrkdwnElement}.
159+
* Maximum length for the text in this field is 150 characters.
160+
*/
161+
subtitle?: MrkdwnElement;
162+
/**
163+
* @description The body text of the card in the form of a {@link MrkdwnElement}.
164+
* Maximum length for the text in this field is 200 characters.
165+
*/
166+
body?: MrkdwnElement;
167+
/**
168+
* @description An array of {@link Button} elements displayed at the bottom of the card.
169+
*/
170+
actions?: Button[];
171+
}
172+
173+
/**
174+
* @description A horizontally scrollable collection of {@link CardBlock} elements.
175+
* @see {@link https://docs.slack.dev/reference/block-kit/blocks/carousel-block Carousel block reference}.
176+
*/
177+
export interface CarouselBlock extends Block {
178+
/**
179+
* @description The type of block. For a carousel block, `type` is always `carousel`.
180+
*/
181+
type: 'carousel';
182+
/**
183+
* @description An array of {@link CardBlock} elements. Minimum 1, maximum 10 cards.
184+
*/
185+
elements: CardBlock[];
186+
}
187+
111188
/**
112189
* A helper union type of all Block Elements that can be used in a {@link ContextBlock}.
113190
* @see {@link https://docs.slack.dev/reference/block-kit/blocks/context-block Context block reference}.
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import { expectAssignable, expectError } from 'tsd';
2+
import type { AlertBlock, CardBlock, CarouselBlock, KnownBlock } from '../src/index';
3+
4+
// CardBlock
5+
// -- sad path
6+
expectError<CardBlock>({}); // missing type
7+
expectError<CardBlock>({ type: 'card', title: { type: 'plain_text', text: 'wrong type' } }); // title must be mrkdwn
8+
// -- happy path
9+
expectAssignable<CardBlock>({ type: 'card' });
10+
expectAssignable<CardBlock>({
11+
type: 'card',
12+
title: { type: 'mrkdwn', text: 'Title' },
13+
});
14+
expectAssignable<CardBlock>({
15+
type: 'card',
16+
icon: { type: 'image', image_url: 'https://example.com/icon.png', alt_text: 'icon' },
17+
title: { type: 'mrkdwn', text: 'Lumon Industries' },
18+
subtitle: { type: 'mrkdwn', text: 'Committed to work-life balance' },
19+
hero_image: { type: 'image', image_url: 'https://example.com/hero.png', alt_text: 'hero' },
20+
body: { type: 'mrkdwn', text: 'Please enjoy each card equally.' },
21+
actions: [{ type: 'button', text: { type: 'plain_text', text: 'Click' }, action_id: 'btn' }],
22+
});
23+
expectAssignable<KnownBlock>({ type: 'card', body: { type: 'mrkdwn', text: 'hi' } });
24+
25+
// AlertBlock
26+
// -- sad path
27+
expectError<AlertBlock>({}); // missing type and text
28+
expectError<AlertBlock>({ type: 'alert' }); // missing required text
29+
// -- happy path
30+
expectAssignable<AlertBlock>({
31+
type: 'alert',
32+
text: { type: 'mrkdwn', text: 'Something happened' },
33+
});
34+
expectAssignable<AlertBlock>({
35+
type: 'alert',
36+
text: { type: 'plain_text', text: 'Simple alert' },
37+
level: 'warning',
38+
});
39+
expectAssignable<KnownBlock>({
40+
type: 'alert',
41+
text: { type: 'mrkdwn', text: 'Notice' },
42+
level: 'error',
43+
});
44+
45+
// CarouselBlock
46+
// -- sad path
47+
expectError<CarouselBlock>({}); // missing type and elements
48+
expectError<CarouselBlock>({ type: 'carousel' }); // missing required elements
49+
// -- happy path
50+
expectAssignable<CarouselBlock>({
51+
type: 'carousel',
52+
elements: [{ type: 'card', title: { type: 'mrkdwn', text: 'Card 1' } }],
53+
});
54+
expectAssignable<CarouselBlock>({
55+
type: 'carousel',
56+
elements: [
57+
{ type: 'card', title: { type: 'mrkdwn', text: 'Card 1' } },
58+
{ type: 'card', body: { type: 'mrkdwn', text: 'Card 2 body' } },
59+
],
60+
});
61+
expectAssignable<KnownBlock>({
62+
type: 'carousel',
63+
elements: [{ type: 'card' }],
64+
});

0 commit comments

Comments
 (0)