1 | import {
|
2 | ForceReply,
|
3 | InlineKeyboardButton,
|
4 | InlineKeyboardMarkup,
|
5 | KeyboardButton,
|
6 | ReplyKeyboardMarkup,
|
7 | ReplyKeyboardRemove,
|
8 | } from './core/types/typegram'
|
9 | import { is2D } from './core/helpers/check'
|
10 |
|
11 | type Hideable<B> = B & { hide?: boolean }
|
12 | type HideableKBtn = Hideable<KeyboardButton>
|
13 | type HideableIKBtn = Hideable<InlineKeyboardButton>
|
14 |
|
15 | export class Markup<
|
16 | T extends
|
17 | | InlineKeyboardMarkup
|
18 | | ReplyKeyboardMarkup
|
19 | | ReplyKeyboardRemove
|
20 | | ForceReply
|
21 | > {
|
22 | constructor(readonly reply_markup: T) {}
|
23 |
|
24 | selective<T extends ForceReply | ReplyKeyboardMarkup>(
|
25 | this: Markup<T>,
|
26 | value = true
|
27 | ) {
|
28 | return new Markup<T>({ ...this.reply_markup, selective: value })
|
29 | }
|
30 |
|
31 | placeholder<T extends ForceReply | ReplyKeyboardMarkup>(
|
32 | this: Markup<T>,
|
33 | placeholder: string
|
34 | ) {
|
35 | return new Markup<T>({
|
36 | ...this.reply_markup,
|
37 | input_field_placeholder: placeholder,
|
38 | })
|
39 | }
|
40 |
|
41 | resize(this: Markup<ReplyKeyboardMarkup>, value = true) {
|
42 | return new Markup<ReplyKeyboardMarkup>({
|
43 | ...this.reply_markup,
|
44 | resize_keyboard: value,
|
45 | })
|
46 | }
|
47 |
|
48 | oneTime(this: Markup<ReplyKeyboardMarkup>, value = true) {
|
49 | return new Markup<ReplyKeyboardMarkup>({
|
50 | ...this.reply_markup,
|
51 | one_time_keyboard: value,
|
52 | })
|
53 | }
|
54 | }
|
55 |
|
56 | export * as button from './button'
|
57 |
|
58 | export function removeKeyboard(): Markup<ReplyKeyboardRemove> {
|
59 | return new Markup<ReplyKeyboardRemove>({ remove_keyboard: true })
|
60 | }
|
61 |
|
62 | export function forceReply(): Markup<ForceReply> {
|
63 | return new Markup<ForceReply>({ force_reply: true })
|
64 | }
|
65 |
|
66 | export function keyboard(buttons: HideableKBtn[][]): Markup<ReplyKeyboardMarkup>
|
67 | export function keyboard(
|
68 | buttons: HideableKBtn[],
|
69 | options?: Partial<KeyboardBuildingOptions<HideableKBtn>>
|
70 | ): Markup<ReplyKeyboardMarkup>
|
71 | export function keyboard(
|
72 | buttons: HideableKBtn[] | HideableKBtn[][],
|
73 | options?: Partial<KeyboardBuildingOptions<HideableKBtn>>
|
74 | ): Markup<ReplyKeyboardMarkup> {
|
75 | const keyboard = buildKeyboard(buttons, {
|
76 | columns: 1,
|
77 | ...options,
|
78 | })
|
79 | return new Markup<ReplyKeyboardMarkup>({ keyboard })
|
80 | }
|
81 |
|
82 | export function inlineKeyboard(
|
83 | buttons: HideableIKBtn[][]
|
84 | ): Markup<InlineKeyboardMarkup>
|
85 | export function inlineKeyboard(
|
86 | buttons: HideableIKBtn[],
|
87 | options?: Partial<KeyboardBuildingOptions<HideableIKBtn>>
|
88 | ): Markup<InlineKeyboardMarkup>
|
89 | export function inlineKeyboard(
|
90 | buttons: HideableIKBtn[] | HideableIKBtn[][],
|
91 | options?: Partial<KeyboardBuildingOptions<HideableIKBtn>>
|
92 | ): Markup<InlineKeyboardMarkup> {
|
93 | const inlineKeyboard = buildKeyboard(buttons, {
|
94 | columns: buttons.length,
|
95 | ...options,
|
96 | })
|
97 | return new Markup<InlineKeyboardMarkup>({ inline_keyboard: inlineKeyboard })
|
98 | }
|
99 |
|
100 | interface KeyboardBuildingOptions<B extends HideableKBtn | HideableIKBtn> {
|
101 | wrap?: (btn: B, index: number, currentRow: B[]) => boolean
|
102 | columns: number
|
103 | }
|
104 |
|
105 | function buildKeyboard<B extends HideableKBtn | HideableIKBtn>(
|
106 | buttons: B[] | B[][],
|
107 | options: KeyboardBuildingOptions<B>
|
108 | ): B[][] {
|
109 | const result: B[][] = []
|
110 | if (!Array.isArray(buttons)) {
|
111 | return result
|
112 | }
|
113 | if (is2D(buttons)) {
|
114 | return buttons.map((row) => row.filter((button) => !button.hide))
|
115 | }
|
116 | const wrapFn =
|
117 | options.wrap !== undefined
|
118 | ? options.wrap
|
119 | : (_btn: B, _index: number, currentRow: B[]) =>
|
120 | currentRow.length >= options.columns
|
121 | let currentRow: B[] = []
|
122 | let index = 0
|
123 | for (const btn of buttons.filter((button) => !button.hide)) {
|
124 | if (wrapFn(btn, index, currentRow) && currentRow.length > 0) {
|
125 | result.push(currentRow)
|
126 | currentRow = []
|
127 | }
|
128 | currentRow.push(btn)
|
129 | index++
|
130 | }
|
131 | if (currentRow.length > 0) {
|
132 | result.push(currentRow)
|
133 | }
|
134 | return result
|
135 | }
|