UNPKG

speedybot

Version:

<p align="center"> <a href="https://github.com/valgaze/speedybot"> <img src="https://img.shields.io/npm/v/speedybot.svg" /> </a> <a href="https://github.com/valgaze/speedybot"> <img src="https://img.shields.io/npm/dm/speedybot.svg" /> </a>

512 lines 16.5 kB
import { CONSTANTS } from "./index"; export const checkers = { isSpeedyCard(input) { return (typeof input === "object" && "build" in input && typeof input.build === "function"); }, isCard(cardCandidate) { if (this.isSpeedyCard(cardCandidate)) { return true; } return ("$schema" in cardCandidate && "type" in cardCandidate && "version" in cardCandidate); }, isEmail(candidate) { const res = candidate.includes("@") && candidate.includes("."); return res; }, }; export const SpeedyCardId = { dropdown: "addPickerDropdown_result", }; export class SpeedyCard { json = { $schema: "http://adaptivecards.io/schemas/adaptive-card.json", type: "AdaptiveCard", version: "1.0", body: [], }; tools = { checkColor(candidate) { const colorMapping = { default: "Default", dark: "Dark", light: "Light", accent: "Accent", good: "Good", warning: "Warning", attention: "Attention", blue: "Accent", red: "Attention", green: "Good", yellow: "Warning", }; const lowerCaseInput = candidate.toLowerCase(); return colorMapping[lowerCaseInput] || "Default"; }, }; _stash = { needsSubmit: false, title: "", subTitle: "", chips: [], data: {}, submitLabel: "Submit", }; id = {}; needsSubmit() { return Boolean(this._stash.needsSubmit); } checkId(id = "") { if (id in this.id) { this.id[id]++; const num = this.id[id]; const modifiedId = `${id}_${num}`; return modifiedId; } else { this.id[id] = 1; return id; } } constructor() { } addTitle(title) { this._stash.title = title; return this; } addSubtitle(subTitle) { this._stash.subTitle = subTitle; return this; } addTable(input, separator = false) { const payload = { type: "FactSet", separator, facts: Array.isArray(input) ? input.map(([label, value]) => ({ title: label, value })) : Object.entries(input).map(([label, value]) => ({ title: label, value, })), }; this.json.body.push(payload); return this; } addChip(payload, id = CONSTANTS.CHIP_LABEL) { return this.addChips([payload], id); } addChips(chips, id = CONSTANTS.CHIP_LABEL) { const chipPayload = chips.map((chip) => { let chipLabel = ""; let chipAction = ""; if (typeof chip === "string") { chipLabel = chip; chipAction = chip; } else { const { title, value = "" } = chip; chipLabel = title; if (value) { chipAction = value; } else { chipAction = title; } } const payload = { type: "Action.Submit", title: chipLabel, data: { [id]: chipAction, }, }; return payload; }); this.json.actions = this.json.actions ? this.json.actions.concat(chipPayload) : chipPayload; return this; } addImage(url, config = {}) { if (url) { const payload = { horizontalAlignment: config.align ?? "Center", size: config.size ?? "ExtraLarge", type: "Image", url, }; if (config.targetURL) { const linkPayload = { type: "Action.OpenUrl", style: "positive", isPrimary: true, url: config.targetURL, }; payload.selectAction = linkPayload; } this.json.body.push(payload); } return this; } addLink(url, label) { return this.addText(`**[${label || url}](${url})**`); } addLinkButton(url, label) { const id = String(Math.random()).slice(3); const cleanId = this.checkId(id); const payload = { type: "Action.OpenUrl", id: cleanId, title: label ?? url, url: url, }; this.addAction(payload); return this; } addText(text, config = {}) { const { bold = false, size = "Medium", align = "Left", color, backgroundColor, vertAlign, } = config; const payload = { type: "TextBlock", text: text, wrap: true, size, horizontalAlignment: align, ...(color && { color: this.tools.checkColor(color) }), ...(bold && { weight: "Bolder" }), }; if (backgroundColor || vertAlign) { const containerPayload = { type: "Container", height: "stretch", items: [payload], ...(backgroundColor && { style: this.tools.checkColor(backgroundColor), }), ...(color && { color: this.tools.checkColor(color) }), ...(vertAlign && { verticalContentAlignment: vertAlign, }), }; this.json.body.push(containerPayload); } else { this.json.body.push(payload); } return this; } addHeader(text, config = {}) { const hasURL = config.iconURL?.includes("http"); const textPayload = { items: [ { type: "TextBlock", text: text, wrap: true, size: config.textSize || "Large", horizontalAlignment: config.textAlign ?? config.rtl ? "Right" : "Left", ...(config.textColor && { color: this.tools.checkColor(config.textColor), }), verticalContentAlignment: "Center", ...(config.backgroundColor && { style: this.tools.checkColor(config.backgroundColor), }), }, ], }; const iconPayload = config.iconURL ? hasURL ? { width: "32px", items: [ { type: "Image", horizontalAlignment: config.iconAlignment ?? "Left", url: config.iconURL, ...(config.iconRound && { style: "person" }), width: `${config.iconWidth ?? "16"}px`, }, ], } : { type: "Column", width: "auto", items: [ { type: "TextBlock", text: config.iconURL, verticalContentAlignment: "Center", }, ], } : null; const headerPayload = { type: "ColumnSet", columns: config.rtl ? [textPayload, iconPayload].filter(Boolean) : [iconPayload, textPayload].filter(Boolean), }; this._stash.header = headerPayload; return this; } addBlock(content, config = {}) { if (typeof content === "string") { return this.addText(content, config); } if (content instanceof SpeedyCard) { const { backgroundColor, vertAlign } = config; const { body } = content.build(); const containerPayload = { ...(config.separator && { separator: config.separator }), type: "Container", height: "stretch", items: body, ...(backgroundColor && { style: this.tools.checkColor(backgroundColor), }), ...(vertAlign && { verticalContentAlignment: vertAlign, }), }; this._stash.needsSubmit = !this._stash.needsSubmit ? content.needsSubmit() : this._stash.needsSubmit; this.json.body.push(containerPayload); } return this; } addSubcard(card, textLabel = "") { const subCard = { type: "Action.ShowCard", title: textLabel, card: "build" in card && typeof card.build === "function" ? card.build() : card, }; this.addAction(subCard); return this; } addPickerDropdown(choices, id = SpeedyCardId.dropdown) { const cleanId = this.checkId(id); this._stash.needsSubmit = true; const formattedChoices = choices.map((choice, idx) => { if (typeof choice === "object") { return choice; } return { title: String(choice), value: String(choice), }; }); const payload = { type: "Input.ChoiceSet", id: cleanId, value: "0", isMultiSelect: false, isVisible: true, choices: formattedChoices, }; this.json.body.push(payload); return this; } addSingleSelect(choices, id = "addSingleSelectresult") { return this.addSelect(choices, id, { isMultiSelect: false, style: "expanded", }); } addMultiSelect(choices, id = "addMultiSelect_result") { return this.addSelect(choices, id, { isMultiSelect: true }); } addSelect(choices, id, config = {}) { this._stash.needsSubmit = true; const cleanId = this.checkId(id); let formattedChoices; if (Array.isArray(choices) && typeof choices[0] === "string") { formattedChoices = choices.map((choice) => ({ title: String(choice), value: String(choice), })); } else { formattedChoices = choices; } const payload = { type: "Input.ChoiceSet", id: cleanId, value: "0", isMultiSelect: Boolean(config.isMultiSelect), isVisible: true, ...(config.style && { style: "expanded" }), choices: formattedChoices, style: "expanded", }; this.json.body.push(payload); return this; } addPickerDate(textLabel, id = "addPickerDate_result") { this._stash.needsSubmit = true; const cleanId = this.checkId(id); const textPayload = this.buildTextPayload(textLabel); const datePicker = { type: "Input.Date", id: cleanId, }; this.json.body.push(textPayload, datePicker); return this; } addPickerTime(textLabel, id = "addPickerTime_result") { this._stash.needsSubmit = true; const cleanId = this.checkId(id); const textPayload = this.buildTextPayload(textLabel); const timePicker = { type: "Input.Time", id: cleanId, }; this.json.body.push(textPayload, timePicker); return this; } addTextInput(placeholder, id = "addTextInput_result") { this._stash.needsSubmit = true; const cleanId = this.checkId(id); const payload = { id: cleanId, placeholder, type: "Input.Text", }; this.json.body.push(payload); return this; } addTextarea(placeholder, id = "addTextarea_result") { this._stash.needsSubmit = true; const cleanId = this.checkId(id); const payload = { id: cleanId, placeholder, type: "Input.Text", isMultiline: true, }; this.json.body.push(payload); return this; } setBackgroundImage(url) { this.json.backgroundImage = url; return this; } setSubmitButtonTitle(label) { this._stash.submitLabel = label; return this; } attachData(payload) { this._stash.needsSubmit = true; this._stash.data = payload; return this; } buildTextPayload(text, textConfig = {}) { const payload = { type: "TextBlock", text, size: "Medium", isSubtle: true, wrap: true, weight: "Lighter", ...textConfig, }; return payload; } addAction(a) { if (!this.json.actions) { this.json.actions = []; } this.json.actions.push(a); } addDeleteButton(label = CONSTANTS.destroyLabel) { return this.addButton(label, CONSTANTS.submitToken, CONSTANTS.action_delete); } addButton(label, id = "button_result", attachedData = {}) { const payload = { type: "Action.Submit", title: label, data: { [id]: attachedData, }, }; this.addAction(payload); return this; } survey(questions, title = "📝 Survey") { const card = new SpeedyCard(); card.addHeader(title); questions.forEach((question, idx) => { let id = question.id || `question_${idx + 1}`; switch (question.type) { case "text": card.addTextInput(question.question, id); break; case "single-select": card.addText(question.question); card.addSingleSelect(question.choices || [], id); break; case "multi-select": card.addText(question.question); card.addMultiSelect(question.choices || [], id); break; case "picker-dropdown": card.addText(question.question); card.addPickerDropdown(question.choices || [], id); break; case "picker-date": card.addPickerDate(question.question, id); break; case "picker-time": card.addPickerTime(question.question, id); break; case "textarea": card.addTextarea(question.question, id); break; } }); return card; } build() { const json = JSON.parse(JSON.stringify(this.json)); const needsSubmit = this._stash.needsSubmit; if (this._stash.subTitle) { json.body.unshift(this.buildTextPayload(this._stash.subTitle)); } if (this._stash.title) { json.body.unshift(this.buildTextPayload(this._stash.title, { weight: "Bolder", size: "ExtraLarge", })); } if (needsSubmit) { const payload = { type: "Action.Submit", title: this._stash.submitLabel, }; if (this._stash.data && Object.keys(this._stash.data).length > 0) { payload.data = this._stash.data; } if (!json.actions) { json.actions = []; } json.actions.push(payload); } const hasHeader = Boolean(this._stash.header); if (hasHeader) { json.body = [ this._stash.header, { separator: true, type: "Container", items: json.body, }, ]; } return json; } } //# sourceMappingURL=cards.js.map