@rilong/grammyjs-conversations-esm 2.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/out/menu.d.ts ADDED
@@ -0,0 +1,593 @@
1
+ import { type Context, type CopyTextButton, type Filter, type InlineKeyboardButton, type InlineKeyboardMarkup, type LoginUrl, type Middleware, type SwitchInlineQueryChosenChat } from "./deps.node.js";
2
+ declare const ops: unique symbol;
3
+ declare const opts: unique symbol;
4
+ /** A handler function for a menu button */
5
+ export type ButtonHandler<C extends Context> = (ctx: C) => unknown | Promise<unknown>;
6
+ /** Options when creating a menu */
7
+ export interface ConversationMenuOptions<C extends Context> {
8
+ /**
9
+ * Identifier of the parent menu. Using a `back` button will navigate to
10
+ * this menu.
11
+ */
12
+ parent?: string | {
13
+ id: string;
14
+ };
15
+ /**
16
+ * Conversational menus will automatically call `ctx.answerCallbackQuery`
17
+ * with no arguments. If you want to call the method yourself, for example
18
+ * because you need to send custom messages, you can set `autoAnswer` to
19
+ * `false` to disable this behavior.
20
+ */
21
+ autoAnswer: boolean;
22
+ /**
23
+ * Fingerprint function that lets you generate a unique string every time a
24
+ * menu is rendered. Used to determine if a menu is outdated. If specified,
25
+ * replaces the built-in heuristic.
26
+ *
27
+ * Using this option is required if you want to enable compatibility with an
28
+ * outside menu defined by the menu plugin. It is rarely useful if you
29
+ * simply want to define a menu inside a conversation.
30
+ *
31
+ * The built-in heuristic that determines whether a menu is outdated takes
32
+ * the following things into account:
33
+ * - identifier of the menu
34
+ * - shape of the menu
35
+ * - position of the pressed button
36
+ * - potential payload
37
+ * - text of the pressed button
38
+ *
39
+ * If all of these things are identical but the menu is still outdated, you
40
+ * can use this option to supply the neccessary data that lets the menu
41
+ * plugin determine more accurately if the menu is outdated. Similarly, if
42
+ * any of these things differ but you want to consider the menu to be up to
43
+ * date, you can also use this option to signal that.
44
+ *
45
+ * In other words, specifying a fingerprint function will replace the above
46
+ * heuristic entirely by your own implementation.
47
+ */
48
+ fingerprint: DynamicString<C>;
49
+ }
50
+ /**
51
+ * A container for many menu instances that are created during a replay of a
52
+ * conversation.
53
+ *
54
+ * You typically do not have to construct this class yourself, but it is used
55
+ * internally in order to provide `conversation.menu` inside conversations.
56
+ */
57
+ export declare class ConversationMenuPool<C extends Context> {
58
+ private index;
59
+ private dirty;
60
+ /**
61
+ * Marks a menu as dirty. When an API call will be performed that edits the
62
+ * specified message, the given menu will be injected into the payload. If
63
+ * no such API happens while processing an update, the all dirty menus will
64
+ * be updated eagerly using `editMessageReplyMarkup`.
65
+ *
66
+ * @param chat_id The chat identifier of the menu
67
+ * @param message_id The message identifier of the menu
68
+ * @param menu The menu to inject into a payload
69
+ */
70
+ markMenuAsDirty(chat_id: string | number, message_id: number, menu?: ConversationMenu<C>): void;
71
+ /**
72
+ * Looks up a dirty menu, returns it, and marks it as clean. Returns
73
+ * undefined if the given message does not have a menu that is marked as
74
+ * dirty.
75
+ *
76
+ * @param chat_id The chat identifier of the menu
77
+ * @param message_id The message identifier of the menu
78
+ */
79
+ getAndClearDirtyMenu(chat_id: string | number, message_id: number): ConversationMenu<C> | undefined;
80
+ /**
81
+ * Creates a new conversational menu with the given identifier and options.
82
+ *
83
+ * If no identifier is specified, an identifier will be auto-generated. This
84
+ * identifier is guaranteed not to clash with any outside menu identifiers
85
+ * used by [the menu plugin](https://grammy.dev/plugins/menu). In contrast,
86
+ * if an identifier is passed that coincides with the identifier of a menu
87
+ * outside the conversation, menu compatibility can be achieved.
88
+ *
89
+ * @param id An optional menu identifier
90
+ * @param options An optional options object
91
+ */
92
+ create(id?: string, options?: Partial<ConversationMenuOptions<C>>): ConversationMenu<C>;
93
+ /**
94
+ * Looks up a menu by its identifier and returns the menu. Throws an error
95
+ * if the identifier cannot be found.
96
+ *
97
+ * @param id The menu identifier to look up
98
+ */
99
+ lookup(id: string | {
100
+ id: string;
101
+ }): ConversationMenu<C>;
102
+ /**
103
+ * Prepares a context object for supporting conversational menus. Returns a
104
+ * function to handle clicks.
105
+ *
106
+ * @param ctx The context object to prepare
107
+ */
108
+ install(ctx: C): {
109
+ handleClicks: () => Promise<{
110
+ next: boolean;
111
+ }>;
112
+ };
113
+ }
114
+ /**
115
+ * Context flavor for context objects in listeners that react to conversational
116
+ * menus. Provides `ctx.menu`, a control pane for the respective conversational
117
+ * menu.
118
+ */
119
+ export interface ConversationMenuFlavor {
120
+ /** Narrows down `ctx.match` to string for menu payloads */
121
+ match?: string;
122
+ /**
123
+ * Control panel for the currently active conversational menu. `ctx.menu` is
124
+ * only available for listeners that are passed as handlers to a
125
+ * conversational menu, and it allows you to perform simple actions such as
126
+ * navigating the menu, or updating or closing it.
127
+ *
128
+ * As an example, if you have a text button that changes its label based on
129
+ * `ctx`, then you should call
130
+ *
131
+ * ```ts
132
+ * ctx.menu.update()
133
+ * ```
134
+ *
135
+ * whenever you mutate some state in such a way that the label should
136
+ * update. The same is true for dynamic ranges that change their layout.
137
+ *
138
+ * If you edit the message yourself after calling one of the functions on
139
+ * `ctx.menu`, the new menu will be automatically injected into the payload.
140
+ * Otherwise, a dedicated API call will be performed after your middleware
141
+ * completes.
142
+ */
143
+ menu: ConversationMenuControlPanel;
144
+ }
145
+ /**
146
+ * Control panel for conversational menus. Can be used to update or close the
147
+ * conversational menu, or to perform manual navigation between conversational
148
+ * menus.
149
+ */
150
+ export interface ConversationMenuControlPanel {
151
+ /**
152
+ * Call this method to update the conversational menu. For instance, if you
153
+ * have a button that changes its text based on `ctx`, then you should call
154
+ * this method to update it.
155
+ *
156
+ * Calling this method will guarantee that the conversational menu is
157
+ * updated, but note that this will perform the update lazily. A new
158
+ * conversational menu is injected into the payload of the request the next
159
+ * time you edit the corresponding message. If you let your middleware
160
+ * complete without editing the message itself again, a dedicated API call
161
+ * will be performed that updates the conversational menu.
162
+ *
163
+ * Pass `{ immediate: true }` to perform the update eagerly instead of
164
+ * lazily. A dedicated API call that updates the conversational menu is sent
165
+ * immediately. In that case, the method returns a Promise that you should
166
+ * `await`. Eager updating may cause flickering of the conversational menu,
167
+ * and it may be slower in some cases.
168
+ */
169
+ update(config: {
170
+ immediate: true;
171
+ }): Promise<void>;
172
+ update(config?: {
173
+ immediate?: false;
174
+ }): void;
175
+ /**
176
+ * Closes the conversational menu. Removes all buttons underneath the
177
+ * message.
178
+ *
179
+ * Calling this method will guarantee that the conversational menu is
180
+ * closed, but note that this will be done lazily. A new conversational menu
181
+ * is injected into the payload of the request the next time you edit the
182
+ * corresponding message. If you let your middleware complete without
183
+ * editing the message itself again, a dedicated API call will be performed
184
+ * that closes the conversational menu.
185
+ *
186
+ * Pass `{ immediate: true }` to perform the update eagerly instead of
187
+ * lazily. A dedicated API call that updates the conversational menu is sent
188
+ * immediately. In that case, the method returns a Promise that you should
189
+ * `await`. Eager closing may be slower in some cases.
190
+ */
191
+ close(config: {
192
+ immediate: true;
193
+ }): Promise<void>;
194
+ close(config?: {
195
+ immediate?: false;
196
+ }): void;
197
+ /**
198
+ * Navigates to the parent menu. By default, the parent menu is the menu on
199
+ * which you called `register` when installing this menu.
200
+ *
201
+ * Throws an error if this menu does not have a parent menu.
202
+ *
203
+ * Calling this method will guarantee that the navigation is performed, but
204
+ * note that this will be done lazily. A new menu is injected into the
205
+ * payload of the request the next time you edit the corresponding message.
206
+ * If you let your middleware complete without editing the message itself
207
+ * again, a dedicated API call will be performed that performs the
208
+ * navigation.
209
+ *
210
+ * Pass `{ immediate: true }` to navigate eagerly instead of lazily. A
211
+ * dedicated API call is sent immediately. In that case, the method returns
212
+ * a Promise that you should `await`. Eager navigation may cause flickering
213
+ * of the menu, and it may be slower in some cases.
214
+ */
215
+ back(config: {
216
+ immediate: true;
217
+ }): Promise<void>;
218
+ back(config?: {
219
+ immediate?: false;
220
+ }): void;
221
+ /**
222
+ * Navigates to the specified conversational submenu. The given identifier
223
+ * is the same string that you pass to `conversation.menu('')`. If you did
224
+ * not pass a string, the identifier will be auto-generated and is
225
+ * accessible via `menu.id`. If you specify the identifier of the current
226
+ * conversational menu itself, this method is equivalent to
227
+ * `ctx.menu.update()`.
228
+ *
229
+ * Calling this method will guarantee that the navigation is performed, but
230
+ * note that this will be done lazily. A new conversational menu is injected
231
+ * into the payload of the request the next time you edit the corresponding
232
+ * message. If you let your middleware complete without editing the message
233
+ * itself again, a dedicated API call will be performed that performs the
234
+ * navigation.
235
+ *
236
+ * Pass `{ immediate: true }` to navigate eagerly instead of lazily. A
237
+ * dedicated API call is sent immediately. In that case, the method returns
238
+ * a Promise that you should `await`. Eager navigation may cause flickering
239
+ * of the conversational menu, and it may be slower in some cases.
240
+ */
241
+ nav(to: string | {
242
+ id: string;
243
+ }, config: {
244
+ immediate: true;
245
+ }): Promise<void>;
246
+ nav(to: string | {
247
+ id: string;
248
+ }, config?: {
249
+ immediate?: false;
250
+ }): void;
251
+ }
252
+ /**
253
+ * Type of context objects received by buttons handlers of conversational menus.
254
+ */
255
+ export type ConversationMenuContext<C extends Context> = Filter<C, "callback_query:data"> & ConversationMenuFlavor;
256
+ /**
257
+ * Middleware that has access to the `ctx.menu` control panel. This is the type
258
+ * of functions that are used as button handlers in conversational menus.
259
+ */
260
+ export type ConversationMenuMiddleware<C extends Context> = Middleware<ConversationMenuContext<C>>;
261
+ type MaybePromise<T> = T | Promise<T>;
262
+ type DynamicString<C extends Context> = (ctx: C) => MaybePromise<string>;
263
+ type MaybeDynamicString<C extends Context> = string | DynamicString<C>;
264
+ interface TextAndPayload<C extends Context> {
265
+ text: MaybeDynamicString<C>;
266
+ payload?: MaybeDynamicString<C>;
267
+ }
268
+ /** A dynamic string, or an object with a text and a payload */
269
+ export type MaybePayloadString<C extends Context> = MaybeDynamicString<C> | TextAndPayload<C>;
270
+ type Cb<C extends Context> = Omit<InlineKeyboardButton.CallbackButton, "callback_data"> & {
271
+ middleware: ConversationMenuMiddleware<C>[];
272
+ payload?: MaybeDynamicString<C>;
273
+ };
274
+ type NoCb = Exclude<InlineKeyboardButton, InlineKeyboardButton.CallbackButton>;
275
+ type RemoveAllTexts<T> = T extends {
276
+ text: string;
277
+ } ? Omit<T, "text"> : T;
278
+ type MakeUrlDynamic<C extends Context, T> = T extends {
279
+ url: string;
280
+ } ? Omit<T, "url"> & {
281
+ url: MaybeDynamicString<C>;
282
+ } : T;
283
+ /**
284
+ * Button of a conversational menu. Almost the same type as InlineKeyboardButton
285
+ * but with texts that can be generated on the fly, and middleware for callback
286
+ * buttons.
287
+ */
288
+ export type MenuButton<C extends Context> = {
289
+ /**
290
+ * Label text on the button, or a function that can generate this text. The
291
+ * function is supplied with the context object that is used to make the
292
+ * request.
293
+ */
294
+ text: MaybeDynamicString<C>;
295
+ } & MakeUrlDynamic<C, RemoveAllTexts<NoCb | Cb<C>>>;
296
+ type RawRange<C extends Context> = MenuButton<C>[][];
297
+ type MaybeRawRange<C extends Context> = ConversationMenuRange<C> | RawRange<C>;
298
+ type DynamicRange<C extends Context> = (ctx: C) => MaybePromise<MaybeRawRange<C>>;
299
+ type MaybeDynamicRange<C extends Context> = MaybeRawRange<C> | DynamicRange<C>;
300
+ /**
301
+ * A conversational menu range is a two-dimensional array of buttons.
302
+ *
303
+ * This array is a part of the total two-dimensional array of buttons. This is
304
+ * mostly useful if you want to dynamically generate the structure of the
305
+ * conversational menu on the fly.
306
+ */
307
+ export declare class ConversationMenuRange<C extends Context> {
308
+ [ops]: MaybeDynamicRange<C>[];
309
+ /**
310
+ * This method is used internally whenever a new range is added.
311
+ *
312
+ * @param range A range object or a two-dimensional array of menu buttons
313
+ */
314
+ addRange(...range: MaybeDynamicRange<C>[]): this;
315
+ /**
316
+ * This method is used internally whenever new buttons are added. Adds the
317
+ * buttons to the current row.
318
+ *
319
+ * @param btns Menu button object
320
+ */
321
+ add(...btns: MenuButton<C>[]): this;
322
+ /**
323
+ * Adds a 'line break'. Call this method to make sure that the next added
324
+ * buttons will be on a new row.
325
+ */
326
+ row(): this;
327
+ /**
328
+ * Adds a new URL button. Telegram clients will open the provided URL when
329
+ * the button is pressed. Note that they will not notify your bot when that
330
+ * happens, so you cannot react to this button.
331
+ *
332
+ * @param text The text to display
333
+ * @param url HTTP or tg:// url to be opened when button is pressed. Links tg://user?id=<user_id> can be used to mention a user by their ID without using a username, if this is allowed by their privacy settings.
334
+ */
335
+ url(text: MaybeDynamicString<C>, url: MaybeDynamicString<C>): this;
336
+ /**
337
+ * Adds a new text button. You may pass any number of listeners. They will
338
+ * be called when the button is pressed.
339
+ *
340
+ * ```ts
341
+ * menu.text('Hit me!', ctx => ctx.reply('Ouch!'))
342
+ * ```
343
+ *
344
+ * If you pass several listeners, make sure that you understand what
345
+ * [middleware](https://grammy.dev/guide/middleware.html) is.
346
+ *
347
+ * You can also use this method to register a button that depends on the
348
+ * current context.
349
+ *
350
+ * ```ts
351
+ * function greetInstruction(ctx: MyConversationContext): string {
352
+ * const username = ctx.from?.first_name
353
+ * return `Greet ${username ?? 'me'}!`,
354
+ * }
355
+ *
356
+ * const menu = conversation.menu()
357
+ * .text(greetInstruction, ctx => ctx.reply("I'm too shy."))
358
+ *
359
+ * // This will send a conversational menu with one text button,
360
+ * // and the text has the name of the user that the bot is replying to.
361
+ * await ctx.reply('What shall I do?', { reply_markup: menu })
362
+ * ```
363
+ *
364
+ * If you base the text on a variable defined inside the conversation, you
365
+ * can easily create a settings panel with toggle buttons.
366
+ *
367
+ * ```ts
368
+ * // Button will toggle between 'Yes' and 'No' when pressed
369
+ * let flag = true
370
+ * menu.text(ctx => flag ? 'Yes' : 'No', async ctx => {
371
+ * flag = !flag
372
+ * ctx.menu.update()
373
+ * })
374
+ * ```
375
+ *
376
+ * @param text The text to display, or a text with payload
377
+ * @param middleware The listeners to call when the button is pressed
378
+ */
379
+ text(text: MaybeDynamicString<C>, ...middleware: ConversationMenuMiddleware<C>[]): this;
380
+ text(text: TextAndPayload<C>, ...middleware: ConversationMenuMiddleware<C & {
381
+ match: string;
382
+ }>[]): this;
383
+ text(text: MaybePayloadString<C>, ...middleware: ConversationMenuMiddleware<C>[]): this;
384
+ /**
385
+ * Adds a new web app button, confer https://core.telegram.org/bots/webapps
386
+ *
387
+ * @param text The text to display
388
+ * @param url An HTTPS URL of a Web App to be opened with additional data
389
+ */
390
+ webApp(text: MaybeDynamicString<C>, url: string): this;
391
+ /**
392
+ * Adds a new login button. This can be used as a replacement for the
393
+ * Telegram Login Widget. You must specify an HTTPS URL used to
394
+ * automatically authorize the user.
395
+ *
396
+ * @param text The text to display
397
+ * @param loginUrl The login URL as string or `LoginUrl` object
398
+ */
399
+ login(text: MaybeDynamicString<C>, loginUrl: string | LoginUrl): this;
400
+ /**
401
+ * Adds a new inline query button. Telegram clients will let the user pick a
402
+ * chat when this button is pressed. This will start an inline query. The
403
+ * selected chat will be prefilled with the name of your bot. You may
404
+ * provide a text that is specified along with it.
405
+ *
406
+ * Your bot will in turn receive updates for inline queries. You can listen
407
+ * to inline query updates like this:
408
+ *
409
+ * ```ts
410
+ * // Listen for specifc query
411
+ * bot.inlineQuery('my-query', ctx => { ... })
412
+ * // Listen for any query
413
+ * bot.on('inline_query', ctx => { ... })
414
+ * ```
415
+ *
416
+ * Technically, it is also possible to wait for an inline query inside the
417
+ * conversation using `conversation.waitFor('inline_query')`. However,
418
+ * updates about inline queries do not contain a chat identifier. Hence, it
419
+ * is typically not possible to handle them inside a conversation, as
420
+ * conversation data is stored per chat by default.
421
+ *
422
+ * @param text The text to display
423
+ * @param query The (optional) inline query string to prefill
424
+ */
425
+ switchInline(text: MaybeDynamicString<C>, query?: string): this;
426
+ /**
427
+ * Adds a new inline query button that acts on the current chat. The
428
+ * selected chat will be prefilled with the name of your bot. You may
429
+ * provide a text that is specified along with it. This will start an inline
430
+ * query.
431
+ *
432
+ * Your bot will in turn receive updates for inline queries. You can listen
433
+ * to inline query updates like this:
434
+ *
435
+ * ```ts
436
+ * // Listen for specifc query
437
+ * bot.inlineQuery('my-query', ctx => { ... })
438
+ * // Listen for any query
439
+ * bot.on('inline_query', ctx => { ... })
440
+ * ```
441
+ *
442
+ * Technically, it is also possible to wait for an inline query inside the
443
+ * conversation using `conversation.waitFor('inline_query')`. However,
444
+ * updates about inline queries do not contain a chat identifier. Hence, it
445
+ * is typically not possible to handle them inside a conversation, as
446
+ * conversation data is stored per chat by default.
447
+ *
448
+ * @param text The text to display
449
+ * @param query The (optional) inline query string to prefill
450
+ */
451
+ switchInlineCurrent(text: MaybeDynamicString<C>, query?: string): this;
452
+ /**
453
+ * Adds a new inline query button. Telegram clients will let the user pick a
454
+ * chat when this button is pressed. This will start an inline query. The
455
+ * selected chat will be prefilled with the name of your bot. You may
456
+ * provide a text that is specified along with it.
457
+ *
458
+ * Your bot will in turn receive updates for inline queries. You can listen
459
+ * to inline query updates like this:
460
+ * ```ts
461
+ * bot.on('inline_query', ctx => { ... })
462
+ * ```
463
+ *
464
+ * Technically, it is also possible to wait for an inline query inside the
465
+ * conversation using `conversation.waitFor('inline_query')`. However,
466
+ * updates about inline queries do not contain a chat identifier. Hence, it
467
+ * is typically not possible to handle them inside a conversation, as
468
+ * conversation data is stored per chat by default.
469
+ *
470
+ * @param text The text to display
471
+ * @param query The query object describing which chats can be picked
472
+ */
473
+ switchInlineChosen(text: MaybeDynamicString<C>, query?: SwitchInlineQueryChosenChat): this;
474
+ /**
475
+ * Adds a new copy text button. When clicked, the specified text will be
476
+ * copied to the clipboard.
477
+ *
478
+ * @param text The text to display
479
+ * @param copyText The text to be copied to the clipboard
480
+ */
481
+ copyText(text: string, copyText: string | CopyTextButton): this;
482
+ /**
483
+ * Adds a new game query button, confer
484
+ * https://core.telegram.org/bots/api#games
485
+ *
486
+ * This type of button must always be the first button in the first row.
487
+ *
488
+ * @param text The text to display
489
+ */
490
+ game(text: MaybeDynamicString<C>): this;
491
+ /**
492
+ * Adds a new payment button, confer
493
+ * https://core.telegram.org/bots/api#payments
494
+ *
495
+ * This type of button must always be the first button in the first row and can only be used in invoice messages.
496
+ *
497
+ * @param text The text to display
498
+ */
499
+ pay(text: MaybeDynamicString<C>): this;
500
+ /**
501
+ * Adds a button that navigates to a given conversational submenu when
502
+ * pressed. You can pass in an instance of another conversational menu, or
503
+ * just the identifier of a conversational menu. This way, you can
504
+ * effectively create a network of conversational menus with navigation
505
+ * between them.
506
+ *
507
+ * You can also navigate to this submenu manually by calling
508
+ * `ctx.menu.nav(menu)`, where `menu` is the target submenu (or its
509
+ * identifier).
510
+ *
511
+ * You can call `submenu.back()` to add a button that navigates back to the
512
+ * parent menu. For this to work, you must specify the `parent` option when
513
+ * creating the conversational menu via `conversation.menu`.
514
+ *
515
+ * @param text The text to display, or a text with payload
516
+ * @param menu The submenu to open, or its identifier
517
+ * @param middleware The listeners to call when the button is pressed
518
+ */
519
+ submenu(text: MaybeDynamicString<C>, menu: string | {
520
+ id: string;
521
+ }, ...middleware: ConversationMenuMiddleware<C>[]): this;
522
+ submenu(text: TextAndPayload<C>, menu: string | {
523
+ id: string;
524
+ }, ...middleware: ConversationMenuMiddleware<C & {
525
+ match: string;
526
+ }>[]): this;
527
+ submenu(text: MaybePayloadString<C>, menu: string | {
528
+ id: string;
529
+ }, ...middleware: ConversationMenuMiddleware<C>[]): this;
530
+ /**
531
+ * Adds a text button that performs a navigation to the parent menu via
532
+ * `ctx.menu.back()`. For this to work, you must specify the `parent` option
533
+ * when creating the conversational menu via `conversation.menu`.
534
+ *
535
+ * @param text The text to display, or a text with payload
536
+ * @param middleware The listeners to call when the button is pressed
537
+ */
538
+ back(text: MaybeDynamicString<C>, ...middleware: ConversationMenuMiddleware<C>[]): this;
539
+ back(text: TextAndPayload<C>, ...middleware: ConversationMenuMiddleware<C & {
540
+ match: string;
541
+ }>[]): this;
542
+ back(text: MaybePayloadString<C>, ...middleware: ConversationMenuMiddleware<C>[]): this;
543
+ /**
544
+ * This is a dynamic way to initialize the conversational menu. A typical
545
+ * use case is when you want to create an arbitrary conversational menu,
546
+ * using the data from your database:
547
+ *
548
+ * ```ts
549
+ * const menu = conversation.menu()
550
+ * const data = await conversation.external(() => fetchDataFromDatabase())
551
+ * menu.dynamic(ctx => data.reduce((range, entry) => range.text(entry)), new ConversationMenuRange())
552
+ * await ctx.reply("Menu", { reply_markup: menu })
553
+ * ```
554
+ *
555
+ * @param menuFactory Async menu factory function
556
+ */
557
+ dynamic(rangeBuilder: (ctx: C, range: ConversationMenuRange<C>) => MaybePromise<MaybeRawRange<C> | void>): this;
558
+ /**
559
+ * Appends a given range to this range. This will effectively replay all
560
+ * operations of the given range onto this range.
561
+ *
562
+ * @param range A potentially raw range
563
+ */
564
+ append(range: MaybeRawRange<C>): this;
565
+ }
566
+ /**
567
+ * A conversational menu is a set of interactive buttons that is displayed
568
+ * beneath a message. It uses an [inline
569
+ * keyboard](https://grammy.dev/plugins/keyboard.html) for that, so in a sense,
570
+ * a conversational menu is just an inline keyboard spiced up with interactivity
571
+ * (such as navigation between multiple pages).
572
+ *
573
+ * ```ts
574
+ * // Create a simple conversational menu
575
+ * const menu = conversation.menu()
576
+ * .text('A', ctx => ctx.reply('You pressed A!')).row()
577
+ * .text('B', ctx => ctx.reply('You pressed B!'))
578
+ *
579
+ * // Send the conversational menu
580
+ * await ctx.reply('Check out this menu:', { reply_markup: menu })
581
+ * ```
582
+ *
583
+ * Check out the [official
584
+ * documentation](https://grammy.dev/plugins/conversations) to see how you can
585
+ * create menus that span several pages, how to navigate between them, and more.
586
+ */
587
+ export declare class ConversationMenu<C extends Context> extends ConversationMenuRange<C> implements InlineKeyboardMarkup {
588
+ readonly id: string;
589
+ [opts]: ConversationMenuOptions<C>;
590
+ constructor(id: string, options?: Partial<ConversationMenuOptions<C>>);
591
+ readonly inline_keyboard: [];
592
+ }
593
+ export {};