UNPKG

botbuilder-core

Version:

Core components for Microsoft Bot Builder. Components in this library can run either in a browser or on the server.

518 lines (495 loc) 20 kB
/** * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. */ import { ActionTypes, AnimationCard, Attachment, AudioCard, CardAction, CardImage, HeroCard, MediaUrl, OAuthCard, O365ConnectorCard, ReceiptCard, SigninCard, ThumbnailCard, TokenExchangeResource, TokenPostResource, VideoCard, } from 'botframework-schema'; /** * Provides methods for formatting the various card types a bot can return. * * @remarks * All of these functions return an [Attachment](xref:botframework-schema.Attachment) object, * which can be added to an existing activity's [attachments](xref:botframework-schema.Activity.attachments) collection directly or * passed as input to one of the [MessageFactory](xref:botbuilder-core.MessageFactory) methods to generate a new activity. * * This example sends a message that contains a single hero card. * * ```javascript * const { MessageFactory, CardFactory } = require('botbuilder'); * * const card = CardFactory.heroCard( * 'White T-Shirt', * ['https://example.com/whiteShirt.jpg'], * ['buy'] * ); * const message = MessageFactory.attachment(card); * await context.sendActivity(message); * ``` */ export class CardFactory { /** * Lists the content type schema for each card style. */ static contentTypes: any = { adaptiveCard: 'application/vnd.microsoft.card.adaptive', animationCard: 'application/vnd.microsoft.card.animation', audioCard: 'application/vnd.microsoft.card.audio', heroCard: 'application/vnd.microsoft.card.hero', receiptCard: 'application/vnd.microsoft.card.receipt', oauthCard: 'application/vnd.microsoft.card.oauth', o365ConnectorCard: 'application/vnd.microsoft.teams.card.o365connector', signinCard: 'application/vnd.microsoft.card.signin', thumbnailCard: 'application/vnd.microsoft.card.thumbnail', videoCard: 'application/vnd.microsoft.card.video', }; /** * Returns an attachment for an Adaptive Card. * * @param card A description of the Adaptive Card to return. * @returns An [Attachment](xref:botframework-schema.Attachment). * @remarks * Adaptive Cards are an open card exchange format enabling developers to exchange UI content in a common and consistent way. * For channels that don't yet support Adaptive Cards natively, the Bot Framework will * down-render the card to an image that's been styled to look good on the target channel. For * channels that support [hero cards](#herocards) you can continue to include Adaptive Card * actions and they will be sent as buttons along with the rendered version of the card. * * For more information about Adaptive Cards and to download the latest SDK, visit * [adaptivecards.io](http://adaptivecards.io/). * * For example: * ```JavaScript * const card = CardFactory.adaptiveCard({ * "$schema": "http://adaptivecards.io/schemas/adaptive-card.json", * "type": "AdaptiveCard", * "version": "1.0", * "body": [ * { * "type": "TextBlock", * "text": "Default text input" * } * ], * "actions": [ * { * "type": "Action.Submit", * "title": "OK" * } * ] * }); * ``` */ static adaptiveCard(card: any): Attachment { return { contentType: CardFactory.contentTypes.adaptiveCard, content: card }; } /** * Returns an attachment for an animation card. * * @param title The card title. * @param media The media URLs for the card. * @param buttons Optional. The array of buttons to include on the card. Each `string` in the array * is converted to an `imBack` button with a title and value set to the value of the string. * @param other Optional. Any additional properties to include on the card. * @returns An [Attachment](xref:botframework-schema.Attachment). */ static animationCard( title: string, media: (MediaUrl | string)[], buttons?: (CardAction | string)[], other?: Partial<AnimationCard>, ): Attachment { return mediaCard(CardFactory.contentTypes.animationCard, title, media, buttons, other); } /** * Returns an attachment for an audio card. * * @param title The card title. * @param media The media URL for the card. * @param buttons Optional. The array of buttons to include on the card. Each `string` in the array * is converted to an `imBack` button with a title and value set to the value of the string. * @param other Optional. Any additional properties to include on the card. * @returns An [Attachment](xref:botframework-schema.Attachment). */ static audioCard( title: string, media: (MediaUrl | string)[], buttons?: (CardAction | string)[], other?: Partial<AudioCard>, ): Attachment { return mediaCard(CardFactory.contentTypes.audioCard, title, media, buttons, other); } /** * Returns an attachment for a hero card. * * @param title The card title. * @param images Optional. The array of images to include on the card. Each element can be a * [CardImage](ref:botframework-schema.CardImage) or the URL of the image to include. * @param buttons Optional. The array of buttons to include on the card. Each `string` in the array * is converted to an `imBack` button with a title and value set to the value of the string. * @param other Optional. Any additional properties to include on the card. * @returns An [Attachment](xref:botframework-schema.Attachment). * @remarks * Hero cards tend to have one dominant, full-width image. * Channels typically render the card's text and buttons below the image. * * For example: * ```javascript * const card = CardFactory.heroCard( * 'White T-Shirt', * ['https://example.com/whiteShirt.jpg'], * ['buy'] * ); * ``` */ static heroCard( title: string, images?: (CardImage | string)[], buttons?: (CardAction | string)[], other?: Partial<HeroCard>, ): Attachment; /** * Returns an attachment for a hero card. * * @param title The card title. * @param text The card text. * @param images Optional. The array of images to include on the card. Each element can be a * [CardImage](ref:botframework-schema.CardImage) or the URL of the image to include. * @param buttons Optional. The array of buttons to include on the card. Each `string` in the array * is converted to an `imBack` button with a title and value set to the value of the string. * @param other Optional. Any additional properties to include on the card. * @returns An [Attachment](xref:botframework-schema.Attachment). * @remarks * Hero cards tend to have one dominant, full-width image. * Channels typically render the card's text and buttons below the image. * For example: * ```javascript * const card = CardFactory.heroCard( * 'White T-Shirt', * ['https://example.com/whiteShirt.jpg'], * ['buy'] * ); * ``` */ static heroCard( title: string, text: string, images?: (CardImage | string)[], buttons?: (CardAction | string)[], other?: Partial<HeroCard>, ): Attachment; /** * Returns an attachment for a hero card. * * @param title The card title. * @param text Optional. The card text. * @param images Optional. The array of images to include on the card. Each element can be a * [CardImage](ref:botframework-schema.CardImage) or the URL of the image to include. * @param buttons Optional. The array of buttons to include on the card. Each `string` in the array * is converted to an `imBack` button with a title and value set to the value of the string. * @param other Optional. Any additional properties to include on the card. * @returns An [Attachment](xref:botframework-schema.Attachment). * @remarks * Hero cards tend to have one dominant, full-width image. * Channels typically render the card's text and buttons below the image. * For example: * ```javascript * const card = CardFactory.heroCard( * 'White T-Shirt', * ['https://example.com/whiteShirt.jpg'], * ['buy'] * ); * ``` */ static heroCard(title: string, text?: any, images?: any, buttons?: any, other?: Partial<HeroCard>): Attachment { const a: Attachment = CardFactory.thumbnailCard(title, text, images, buttons, other); a.contentType = CardFactory.contentTypes.heroCard; return a; } /** * Returns an attachment for an OAuth card. * * @param connectionName The name of the OAuth connection to use. * @param title The title for the card's sign-in button. * @param text Optional. Additional text to include on the card. * @param link Optional. The sign-in link to use. * @param tokenExchangeResource optional. The resource to try to perform token exchange with. * @param tokenPostResource optional. The resource for directly post a token to token service. * @returns An [Attachment](xref:botframework-schema.Attachment). * @remarks OAuth cards support the Bot Framework's single sign on (SSO) service. */ static oauthCard( connectionName: string, title: string, text?: string, link?: string, tokenExchangeResource?: TokenExchangeResource, tokenPostResource?: TokenPostResource, ): Attachment { const card: Partial<OAuthCard> = { buttons: [{ type: ActionTypes.Signin, title: title, value: link, channelData: undefined }], connectionName, tokenExchangeResource, tokenPostResource, }; if (text) { card.text = text; } return { contentType: CardFactory.contentTypes.oauthCard, content: card }; } /** * Returns an attachment for an Office 365 connector card. * * @param card a description of the Office 365 connector card to return. * @returns An [Attachment](xref:botframework-schema.Attachment). * @remarks * For example: * ```JavaScript * const card = CardFactory.o365ConnectorCard({ * "title": "card title", * "text": "card text", * "summary": "O365 card summary", * "themeColor": "#E67A9E", * "sections": [ * { * "title": "**section title**", * "text": "section text", * "activityTitle": "activity title", * } * ] * }); * ``` */ static o365ConnectorCard(card: O365ConnectorCard): Attachment { return { contentType: CardFactory.contentTypes.o365ConnectorCard, content: card }; } /** * Returns an attachment for a receipt card. * * @param card A description of the receipt card to return. * @returns An [Attachment](xref:botframework-schema.Attachment). */ static receiptCard(card: ReceiptCard): Attachment { return { contentType: CardFactory.contentTypes.receiptCard, content: card }; } /** * Returns an attachment for a sign-in card. * * @param title The title for the card's sign-in button. * @param url The URL of the sign-in page to use. * @param text Optional. Additional text to include on the card. * @returns An [Attachment](xref:botframework-schema.Attachment). * @remarks * For channels that don't natively support sign-in cards, an alternative message is rendered. */ static signinCard(title: string, url: string, text?: string): Attachment { const card: SigninCard = { buttons: [{ type: ActionTypes.Signin, title: title, value: url, channelData: undefined }], }; if (text) { card.text = text; } return { contentType: CardFactory.contentTypes.signinCard, content: card }; } /** * Returns an attachment for a thumbnail card. * * @param title The card title. * @param images Optional. The array of images to include on the card. Each element can be a * [CardImage](ref:botframework-schema.CardImage) or the URL of the image to include. * @param buttons Optional. The array of buttons to include on the card. Each `string` in the array * is converted to an `imBack` button with a title and value set to the value of the string. * @param other Optional. Any additional properties to include on the card. * @returns An [Attachment](xref:botframework-schema.Attachment). * @remarks * Thumbnail cards are similar to hero cards but instead of a full width image, * they're typically rendered with a smaller thumbnail version of the image. * Channels typically render the card's text to one side of the image, * with any buttons displayed below the card. */ static thumbnailCard( title: string, images?: (CardImage | string)[], buttons?: (CardAction | string)[], other?: Partial<ThumbnailCard>, ): Attachment; /** * Returns an attachment for a thumbnail card. * * @param title The card title. * @param text The card text. * @param images Optional. The array of images to include on the card. Each element can be a * [CardImage](ref:botframework-schema.CardImage) or the URL of the image to include. * @param buttons Optional. The array of buttons to include on the card. Each `string` in the array * is converted to an `imBack` button with a title and value set to the value of the string. * @param other Optional. Any additional properties to include on the card. * @returns An [Attachment](xref:botframework-schema.Attachment). * @remarks * Thumbnail cards are similar to hero cards but instead of a full width image, * they're typically rendered with a smaller thumbnail version of the image. * Channels typically render the card's text to one side of the image, * with any buttons displayed below the card. */ static thumbnailCard( title: string, text: string, images?: (CardImage | string)[], buttons?: (CardAction | string)[], other?: Partial<ThumbnailCard>, ): Attachment; /** * Returns an attachment for a thumbnail card. * * @param title The card title. * @param text Optional. The card text. * @param images Optional. The array of images to include on the card. Each element can be a * [CardImage](ref:botframework-schema.CardImage) or the URL of the image to include. * @param buttons Optional. The array of buttons to include on the card. Each `string` in the array * is converted to an `imBack` button with a title and value set to the value of the string. * @param other Optional. Any additional properties to include on the card. * @returns An [Attachment](xref:botframework-schema.Attachment). * @remarks * Thumbnail cards are similar to hero cards but instead of a full width image, * they're typically rendered with a smaller thumbnail version of the image. * Channels typically render the card's text to one side of the image, * with any buttons displayed below the card. */ static thumbnailCard( title: string, text?: any, images?: any, buttons?: any, other?: Partial<ThumbnailCard>, ): Attachment { if (typeof text !== 'string') { other = buttons; buttons = images; images = text; text = undefined; } const card: Partial<ThumbnailCard> = { ...other }; if (title) { card.title = title; } if (text) { card.text = text; } if (images) { card.images = CardFactory.images(images); } if (buttons) { card.buttons = CardFactory.actions(buttons); } return { contentType: CardFactory.contentTypes.thumbnailCard, content: card }; } /** * Returns an attachment for a video card. * * @param title The card title. * @param media The media URLs for the card. * @param buttons Optional. The array of buttons to include on the card. Each `string` in the array * is converted to an `imBack` button with a title and value set to the value of the string. * @param other Optional. Any additional properties to include on the card. * @returns An [Attachment](xref:botframework-schema.Attachment). */ static videoCard( title: string, media: (MediaUrl | string)[], buttons?: (CardAction | string)[], other?: Partial<VideoCard>, ): Attachment { return mediaCard(CardFactory.contentTypes.videoCard, title, media, buttons, other); } /** * Returns a properly formatted array of actions. * * @param actions The array of action to include on the card. Each `string` in the array * is converted to an `imBack` button with a title and value set to the value of the string. * @returns A properly formatted array of actions. */ static actions(actions: (CardAction | string)[] | undefined): CardAction[] { const list: CardAction[] = []; (actions || []).forEach((a: CardAction | string) => { if (typeof a === 'object') { list.push(a); } else { list.push({ type: ActionTypes.ImBack, value: a.toString(), title: a.toString(), channelData: undefined, }); } }); return list; } /** * Returns a properly formatted array of card images. * * @param images The array of images to include on the card. Each element can be a * [CardImage](ref:botframework-schema.CardImage) or the URL of the image to include. * @returns A properly formatted array of card images. */ static images(images: (CardImage | string)[] | undefined): CardImage[] { const list: CardImage[] = []; (images || []).forEach((img: CardImage | string) => { if (typeof img === 'object') { list.push(img); } else { list.push({ url: img }); } }); return list; } /** * Returns a properly formatted array of media URL objects. * * @param links The media URLs. Each `string` is converted to a media URL object. * @returns A properly formatted array of media URL objects. */ static media(links: (MediaUrl | string)[] | undefined): MediaUrl[] { const list: MediaUrl[] = []; (links || []).forEach((lnk: MediaUrl | string) => { if (typeof lnk === 'object') { list.push(lnk); } else { list.push({ url: lnk }); } }); return list; } } /** * @private */ function mediaCard( contentType: string, title: string, media: (MediaUrl | string)[], buttons?: (CardAction | string)[], other?: any, ): Attachment { const card: VideoCard = { ...other }; if (title) { card.title = title; } card.media = CardFactory.media(media); if (buttons) { card.buttons = CardFactory.actions(buttons); } return { contentType: contentType, content: card }; }