Skip to content

Commit

Permalink
types: export helper union types (#1819)
Browse files Browse the repository at this point in the history
  • Loading branch information
filmaj authored Jun 14, 2024
1 parent 1583183 commit f8d06ca
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 41 deletions.
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;

// 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

0 comments on commit f8d06ca

Please sign in to comment.