feat(client): bot keyboard builder

This commit is contained in:
teidesu 2021-07-06 01:11:06 +03:00
parent 6215892090
commit 36ba4c3b87
3 changed files with 111 additions and 0 deletions

View file

@ -5,3 +5,4 @@ export * from './inline-query'
export * from './callback-query' export * from './callback-query'
export * from './game-high-score' export * from './game-high-score'
export * from './command-scope' export * from './command-scope'
export * from './keyboard-builder'

View file

@ -0,0 +1,105 @@
import type { InlineKeyboardMarkup, ReplyKeyboardMarkup } from './keyboards'
import { tl } from '@mtcute/tl'
type ButtonLike = tl.TypeKeyboardButton | false | null | undefined | void
/**
* Builder for bot keyboards
*/
export class BotKeyboardBuilder {
private _buttons: tl.TypeKeyboardButton[][] = []
constructor(readonly maxRowWidth: number | null = 3) {}
/**
* Add buttons, wrapping them once {@link maxRowWidth} is reached
*
* @param buttons Buttons to add
*/
push(...buttons: (ButtonLike | (() => ButtonLike))[]): this {
if (!buttons.length) return this
let row: tl.TypeKeyboardButton[] = []
buttons.forEach((btn) => {
if (typeof btn === 'function') btn = btn()
if (!btn) return
row.push(btn)
if (row.length === this.maxRowWidth) {
this._buttons.push(row)
row = []
}
})
if (row.length) {
this._buttons.push(row)
}
return this
}
/**
* Add a row of buttons. Will not be wrapped.
*
* @param row Row or a function that will populate it
*/
row(row: ButtonLike[] | ((arr: ButtonLike[]) => void)): this {
if (typeof row === 'function') {
const fn = row
row = []
fn(row)
}
const normal = row.filter(Boolean) as tl.TypeKeyboardButton[]
if (normal.length) this._buttons.push(normal)
return this
}
/**
* Append a button to the last row, wrapping if needed.
*
* @param btn Button to add
* @param force Whether to forcefully add the button (i.e. do not wrap)
*/
append(btn: ButtonLike | (() => ButtonLike), force = false): this {
if (typeof btn === 'function') btn = btn()
if (!btn) return this
if (
this._buttons.length &&
(this.maxRowWidth === null ||
force ||
this._buttons[this._buttons.length - 1].length <
this.maxRowWidth)
) {
this._buttons[this._buttons.length - 1].push()
} else {
this._buttons.push([btn])
}
return this
}
/**
* Return contents of this builder as an inline keyboard
*/
asInline(): InlineKeyboardMarkup {
return {
type: 'inline',
buttons: this._buttons,
}
}
/**
* Return contents of this builder as a reply keyboard
*/
asReply(
params: Omit<ReplyKeyboardMarkup, 'type' | 'buttons'> = {}
): ReplyKeyboardMarkup {
const ret = params as tl.Mutable<ReplyKeyboardMarkup>
ret.type = 'reply'
ret.buttons = this._buttons
return ret
}
}

View file

@ -1,4 +1,5 @@
import { tl } from '@mtcute/tl' import { tl } from '@mtcute/tl'
import { BotKeyboardBuilder } from './keyboard-builder'
/** /**
* Reply keyboard markup * Reply keyboard markup
@ -57,6 +58,10 @@ export type ReplyMarkup =
* > in the description. * > in the description.
*/ */
export namespace BotKeyboard { export namespace BotKeyboard {
export function builder(maxRowWidth?: number | null): BotKeyboardBuilder {
return new BotKeyboardBuilder(maxRowWidth)
}
/** /**
* Create an inline keyboard markup * Create an inline keyboard markup
* *