Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

types: export helper union types #1819

Merged
merged 4 commits into from
Jun 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
106 changes: 73 additions & 33 deletions packages/types/src/block-kit/blocks.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
// This file contains objects documented here: https://api.slack.com/reference/block-kit/blocks

import {
PlainTextElement,
MrkdwnElement,
TextObject,
UrlImageObject,
SlackFileImageObject,
} from './composition-objects';
import { Actionable } from './extensions';
import {
Button,
Checkboxes,
Expand All @@ -32,6 +30,9 @@ import {
} from './block-elements';

export interface Block {
/**
* @description The type of block.
*/
type: string;
/**
* @description A string acting as a unique identifier for a block. If not specified, a `block_id` will be generated.
Expand All @@ -43,8 +44,24 @@ export interface Block {
block_id?: string;
}

/**
* A helper union type of all known Blocks, as listed out on the
* {@link https://api.slack.com/reference/block-kit/blocks Blocks reference}.
*/
export type KnownBlock = ImageBlock | ContextBlock | ActionsBlock | DividerBlock |
SectionBlock | InputBlock | FileBlock | HeaderBlock | VideoBlock | RichTextBlock;
/**
* A helper union type of all known Blocks as well as the generic {@link Block} interface. A full list of known blocks
* is available here: {@link https://api.slack.com/reference/block-kit/blocks Blocks reference}.
*/
export type AnyBlock = KnownBlock | Block;

/**
* A helper union type of all Block Elements that can be used in an {@link ActionsBlock}.
* @see {@link https://api.slack.com/reference/block-kit/blocks#actions Actions block reference}.
*/
export type ActionsBlockElement = Button | Checkboxes | Datepicker | DateTimepicker | MultiSelect | Overflow |
RadioButtons | Select | Timepicker | WorkflowButton | RichTextInput;

/**
* @description Holds multiple interactive elements.
Expand All @@ -59,10 +76,15 @@ export interface ActionsBlock extends Block {
* @description An array of {@link InteractiveElements} objects.
* There is a maximum of 25 elements in each action block.
*/
elements: (Button | Checkboxes | Datepicker | DateTimepicker | MultiSelect | Overflow | RadioButtons | Select |
Timepicker | WorkflowButton | RichTextInput)[];
elements: ActionsBlockElement[]; // TODO: breaking change: min 1 item
}

/**
* A helper union type of all Block Elements that can be used in a {@link ContextBlock}.
* @see {@link https://api.slack.com/reference/block-kit/blocks#context Context block reference}.
*/
export type ContextBlockElement = ImageElement | TextObject;

/**
* @description Displays contextual info, which can include both images and text.
* @see {@link https://api.slack.com/reference/block-kit/blocks#context Context block reference}.
Expand All @@ -72,12 +94,11 @@ export interface ContextBlock extends Block {
* @description The type of block. For a context block, `type` is always `context`.
*/
type: 'context';
// TODO: use the future planned plaintext/mrkdwn union here instead
/**
* @description An array of {@link ImageElement}, {@link PlainTextElement} or {@link MrkdwnElement} objects.
* Maximum number of items is 10.
*/
elements: (ImageElement | PlainTextElement | MrkdwnElement)[];
elements: ContextBlockElement[]; // TODO: breaking change: min 1 item
}

/**
Expand Down Expand Up @@ -107,7 +128,7 @@ export interface FileBlock extends Block {
/**
* @description At the moment, source will always be `remote` for a remote file.
*/
source: string; // TODO: breaking change: set this to the string literal 'remote' ?
source: string; // TODO: breaking change: set this to the string literal 'remote'
/**
* @description The external unique ID for this file.
*/
Expand Down Expand Up @@ -152,6 +173,13 @@ export type ImageBlock = {
title?: PlainTextElement;
} & Block & (UrlImageObject | SlackFileImageObject);

/**
* A helper union type of all Block Elements that can be used in an {@link InputBlock}.
* @see {@link https://api.slack.com/reference/block-kit/blocks#input Input block reference}.
*/
export type InputBlockElement = Checkboxes | Datepicker | DateTimepicker | EmailInput | FileInput | MultiSelect |
NumberInput | PlainTextInput | RadioButtons | RichTextInput | Select | Timepicker | URLInput;

/**
* @description Collects information from users via block elements.
* @see {@link https://api.slack.com/reference/block-kit/blocks#input Input block reference}.
Expand Down Expand Up @@ -181,15 +209,44 @@ export interface InputBlock extends Block {
/**
* @description A block element.
*/
element: Select | MultiSelect | Datepicker | Timepicker | DateTimepicker | PlainTextInput | URLInput | EmailInput
| NumberInput | RadioButtons | Checkboxes | RichTextInput | FileInput;
element: InputBlockElement;
/**
* @description A boolean that indicates whether or not the use of elements in this block should dispatch a
* {@link https://api.slack.com/reference/interaction-payloads/block-actions block_actions payload}. Defaults to `false`.
*/
dispatch_action?: boolean;
}

/**
* A helper union type of all Block Elements that can be used in a {@link RichTextBlock}.
* @see {@link https://api.slack.com/reference/block-kit/blocks#rich_text Rich text block reference}.
*/
export type RichTextBlockElement = RichTextSection | RichTextList | RichTextQuote | RichTextPreformatted;

/**
* @description Displays formatted, structured representation of text. It is also the output of the Slack client's
* WYSIWYG message composer, so all messages sent by end-users will have this format. Use this block to include
* user-defined formatted text in your Block Kit payload. While it is possible to format text with `mrkdwn`,
* `rich_text` is strongly preferred and allows greater flexibility.
* You might encounter a `rich_text` block in a message payload, as a built-in type in workflow apps, or as output of
* the {@link RichTextInput}.
* @see {@link https://api.slack.com/reference/block-kit/blocks#rich_text Rich text block reference}.
*/
export interface RichTextBlock extends Block {
/**
* @description The type of block. For a rich text block, `type` is always `rich_text`.
*/
type: 'rich_text',
elements: RichTextBlockElement[];
}

/**
* A helper union type of all Block Elements that can be used as an accessory in a {@link SectionBlock}.
* @see {@link https://api.slack.com/reference/block-kit/blocks#section Section block reference}.
*/
export type SectionBlockAccessory = Button | Checkboxes | Datepicker | ImageElement | MultiSelect | Overflow |
RadioButtons | Select | Timepicker | WorkflowButton;
Comment on lines +247 to +248
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great to see these ordered and matching the docs 🙌


// TODO: breaking change: use a discriminative union to represent section block using `text` or `fields` but
// not both or neither.
/**
Expand All @@ -204,31 +261,22 @@ export interface SectionBlock extends Block {
*/
type: 'section';
/**
* @description The text for the block, in the form of a text object. Minimum length for the `text` in this field is
* 1 and maximum length is 3000 characters. This field is not required if a valid array of `fields` objects is
* provided instead.
* @description The text for the block, in the form of a {@link TextObject}. Minimum length for the `text` in this
* field is 1 and maximum length is 3000 characters. This field is not required if a valid array of `fields` objects
* is provided instead.
*/
text?: PlainTextElement | MrkdwnElement;
text?: TextObject;
/**
* @description Required if no `text` is provided. An array of text objects. Any text objects included with `fields`
* will be rendered in a compact format that allows for 2 columns of side-by-side text. Maximum number of items is 10.
* Maximum length for the text in each item is 2000 characters.
* {@link https://app.slack.com/block-kit-builder/#%7B%22blocks%22:%5B%7B%22type%22:%22section%22,%22text%22:%7B%22text%22:%22A%20message%20*with%20some%20bold%20text*%20and%20_some%20italicized%20text_.%22,%22type%22:%22mrkdwn%22%7D,%22fields%22:%5B%7B%22type%22:%22mrkdwn%22,%22text%22:%22*Priority*%22%7D,%7B%22type%22:%22mrkdwn%22,%22text%22:%22*Type*%22%7D,%7B%22type%22:%22plain_text%22,%22text%22:%22High%22%7D,%7B%22type%22:%22plain_text%22,%22text%22:%22String%22%7D%5D%7D%5D%7D Click here for an example}.
*/
fields?: (PlainTextElement | MrkdwnElement)[]; // either this or text must be defined
fields?: TextObject[]; // either this or text must be defined, also min 1 item
/**
* @description One of the compatible element objects.
*/
accessory?: Button
| Overflow
| Datepicker
| Timepicker
| Select
| MultiSelect
| Actionable
| ImageElement
| RadioButtons
| Checkboxes;
accessory?: SectionBlockAccessory;
}

/**
Expand Down Expand Up @@ -282,11 +330,3 @@ export interface VideoBlock extends Block {
*/
description?: PlainTextElement;
}

export interface RichTextBlock extends Block {
/**
* @description The type of block. For a rich text block, `type` is always `rich_text`.
*/
type: 'rich_text',
elements: (RichTextSection | RichTextList | RichTextQuote | RichTextPreformatted)[];
}
9 changes: 7 additions & 2 deletions packages/types/src/block-kit/composition-objects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,13 @@ export interface OptionGroup {
options: Option[];
}

// TODO: (additive change) maybe worth adding a TextObject union for both PlainTextElement and MrkdwnElement, if they
// are meant to be used this way, as they seem to be documented together? https://api.slack.com/reference/block-kit/composition-objects#text
/**
* @description Defines an object containing some text. Can be either a {@link PlainTextElement} or a
* {@link MrkdwnElement}.
* @see {@link https://api.slack.com/reference/block-kit/composition-objects#text Text object reference}.
*/
export type TextObject = PlainTextElement | MrkdwnElement;

/**
* @description Defines an object containing some text.
* @see {@link https://api.slack.com/reference/block-kit/composition-objects#text Text object reference}.
Expand Down
4 changes: 2 additions & 2 deletions packages/types/src/message-attachments.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { PlainTextElement } from './block-kit/composition-objects';
import { Block, KnownBlock } from './block-kit/blocks';
import { AnyBlock } from './block-kit/blocks';

// TODO: breaking changes, use discriminated union for `fallback`, `text` and `block` properties, maybe LegacyAttachment
// vs. BlocksAttachment? as per https://api.slack.com/reference/messaging/attachments#legacy_fields
Expand All @@ -18,7 +18,7 @@ export interface MessageAttachment {
* @description An array of {@link KnownBlock layout blocks} in the same format
* {@link https://api.slack.com/block-kit/building as described in the building blocks guide}.
*/
blocks?: (KnownBlock | Block)[];
blocks?: AnyBlock[];
/**
* @description A plain text summary of the attachment used in clients that
* don't show formatted text (e.g. mobile notifications).
Expand Down
8 changes: 4 additions & 4 deletions packages/types/src/views.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { Block, KnownBlock } from './block-kit/blocks';
import { AnyBlock } from './block-kit/blocks';
import { PlainTextElement } from './block-kit/composition-objects';

// Reference: https://api.slack.com/surfaces/app-home#composing
export interface HomeView {
type: 'home';
blocks: (KnownBlock | Block)[];
blocks: AnyBlock[];
private_metadata?: string;
callback_id?: string;
external_id?: string;
Expand All @@ -14,7 +14,7 @@ export interface HomeView {
export interface ModalView {
type: 'modal';
title: PlainTextElement;
blocks: (KnownBlock | Block)[];
blocks: AnyBlock[];
close?: PlainTextElement;
submit?: PlainTextElement;
private_metadata?: string;
Expand All @@ -30,7 +30,7 @@ export interface ModalView {
*/
export interface WorkflowStepView {
type: 'workflow_step';
blocks: (KnownBlock | Block)[];
blocks: AnyBlock[];
private_metadata?: string;
callback_id?: string;
submit_disabled?: boolean; // defaults to false
Expand Down
Loading