telegix 1.1.1 → 1.1.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.
@@ -0,0 +1,256 @@
1
+ /**
2
+ * Telegix - Adjustable Link Preview Builder (Bot API 7.0+)
3
+ * Provides fluent options to control link preview rendering, media size,
4
+ * positioning above/below text, or disabling link previews.
5
+ * @module telegix/link-preview
6
+ */
7
+
8
+ export class LinkPreview {
9
+ /**
10
+ * @param {object} [options]
11
+ * @param {boolean} [options.is_disabled]
12
+ * @param {string} [options.url]
13
+ * @param {boolean} [options.prefer_small_media]
14
+ * @param {boolean} [options.prefer_large_media]
15
+ * @param {boolean} [options.show_above_text]
16
+ */
17
+ constructor(options = {}) {
18
+ this._options = { ...options };
19
+ }
20
+
21
+ /**
22
+ * Disable the link preview entirely
23
+ * @param {boolean} [disabled=true]
24
+ * @returns {this}
25
+ */
26
+ disable(disabled = true) {
27
+ if (disabled) {
28
+ this._options.is_disabled = true;
29
+ } else {
30
+ delete this._options.is_disabled;
31
+ }
32
+ return this;
33
+ }
34
+
35
+ /**
36
+ * Set specific URL to preview
37
+ * @param {string} url
38
+ * @returns {this}
39
+ */
40
+ url(url) {
41
+ this._options.url = String(url);
42
+ return this;
43
+ }
44
+
45
+ /**
46
+ * Shrink preview media into a small square thumbnail
47
+ * @param {boolean} [prefer=true]
48
+ * @returns {this}
49
+ */
50
+ smallMedia(prefer = true) {
51
+ if (prefer) {
52
+ this._options.prefer_small_media = true;
53
+ delete this._options.prefer_large_media;
54
+ } else {
55
+ delete this._options.prefer_small_media;
56
+ }
57
+ return this;
58
+ }
59
+
60
+ /**
61
+ * Expand preview media into a large preview card
62
+ * @param {boolean} [prefer=true]
63
+ * @returns {this}
64
+ */
65
+ largeMedia(prefer = true) {
66
+ if (prefer) {
67
+ this._options.prefer_large_media = true;
68
+ delete this._options.prefer_small_media;
69
+ } else {
70
+ delete this._options.prefer_large_media;
71
+ }
72
+ return this;
73
+ }
74
+
75
+ /**
76
+ * Position the link preview card ABOVE the message text
77
+ * @param {boolean} [above=true]
78
+ * @returns {this}
79
+ */
80
+ showAbove(above = true) {
81
+ if (above) {
82
+ this._options.show_above_text = true;
83
+ } else {
84
+ delete this._options.show_above_text;
85
+ }
86
+ return this;
87
+ }
88
+
89
+ /**
90
+ * Position the link preview card ABOVE the message text (alias)
91
+ * @param {boolean} [above=true]
92
+ * @returns {this}
93
+ */
94
+ aboveText(above = true) {
95
+ return this.showAbove(above);
96
+ }
97
+
98
+ /**
99
+ * Position the link preview card BELOW the message text
100
+ * @param {boolean} [below=true]
101
+ * @returns {this}
102
+ */
103
+ showBelow(below = true) {
104
+ if (below) {
105
+ delete this._options.show_above_text;
106
+ } else {
107
+ this._options.show_above_text = true;
108
+ }
109
+ return this;
110
+ }
111
+
112
+ /**
113
+ * Position the link preview card BELOW the message text (alias)
114
+ * @param {boolean} [below=true]
115
+ * @returns {this}
116
+ */
117
+ belowText(below = true) {
118
+ return this.showBelow(below);
119
+ }
120
+
121
+ /**
122
+ * Disable the link preview entirely (alias)
123
+ * @param {boolean} [disabled=true]
124
+ * @returns {this}
125
+ */
126
+ disabled(disabled = true) {
127
+ return this.disable(disabled);
128
+ }
129
+
130
+ /**
131
+ * Enable the link preview
132
+ * @returns {this}
133
+ */
134
+ enable() {
135
+ return this.disable(false);
136
+ }
137
+
138
+ /**
139
+ * Returns LinkPreviewOptions payload object
140
+ * @returns {object}
141
+ */
142
+ toJSON() {
143
+ const res = {};
144
+ if (this._options.is_disabled !== undefined && this._options.is_disabled !== null) {
145
+ res.is_disabled = Boolean(this._options.is_disabled);
146
+ }
147
+ if (this._options.url) {
148
+ res.url = String(this._options.url);
149
+ }
150
+ if (this._options.prefer_small_media) {
151
+ res.prefer_small_media = true;
152
+ }
153
+ if (this._options.prefer_large_media) {
154
+ res.prefer_large_media = true;
155
+ }
156
+ if (this._options.show_above_text) {
157
+ res.show_above_text = true;
158
+ }
159
+ return res;
160
+ }
161
+
162
+ /**
163
+ * Wraps as Telegram extra parameter
164
+ * @returns {{ link_preview_options: object }}
165
+ */
166
+ toExtra() {
167
+ return {
168
+ link_preview_options: this.toJSON(),
169
+ };
170
+ }
171
+
172
+ // --- Static Factory Methods ---
173
+
174
+ /**
175
+ * Create LinkPreview builder instance
176
+ * @param {string|object} [urlOrOptions]
177
+ * @param {object} [options]
178
+ * @returns {LinkPreview}
179
+ */
180
+ static create(urlOrOptions, options = {}) {
181
+ if (typeof urlOrOptions === 'string') {
182
+ const lp = new LinkPreview(options);
183
+ lp.url(urlOrOptions);
184
+ return lp;
185
+ }
186
+ if (typeof urlOrOptions === 'object' && urlOrOptions !== null) {
187
+ return new LinkPreview({ ...urlOrOptions, ...options });
188
+ }
189
+ return new LinkPreview(options);
190
+ }
191
+
192
+ /**
193
+ * Create LinkPreview with options
194
+ * @param {object} options
195
+ * @returns {LinkPreview}
196
+ */
197
+ static options(options = {}) {
198
+ return new LinkPreview(options);
199
+ }
200
+
201
+ /**
202
+ * Create disabled link preview options
203
+ * @returns {LinkPreview}
204
+ */
205
+ static disabled() {
206
+ return new LinkPreview({ is_disabled: true });
207
+ }
208
+
209
+ /**
210
+ * Create link preview with small media thumbnail
211
+ * @param {string} [url]
212
+ * @param {boolean} [showAbove=false]
213
+ * @returns {LinkPreview}
214
+ */
215
+ static small(url, showAbove = false) {
216
+ const lp = new LinkPreview({ prefer_small_media: true, show_above_text: Boolean(showAbove) });
217
+ if (url) lp.url(url);
218
+ return lp;
219
+ }
220
+
221
+ /**
222
+ * Create link preview with large media card
223
+ * @param {string} [url]
224
+ * @param {boolean} [showAbove=false]
225
+ * @returns {LinkPreview}
226
+ */
227
+ static large(url, showAbove = false) {
228
+ const lp = new LinkPreview({ prefer_large_media: true, show_above_text: Boolean(showAbove) });
229
+ if (url) lp.url(url);
230
+ return lp;
231
+ }
232
+
233
+ /**
234
+ * Create link preview positioned above message text
235
+ * @param {string} [url]
236
+ * @param {object} [options]
237
+ * @returns {LinkPreview}
238
+ */
239
+ static above(url, options = {}) {
240
+ const lp = new LinkPreview({ show_above_text: true, ...options });
241
+ if (url) lp.url(url);
242
+ return lp;
243
+ }
244
+
245
+ /**
246
+ * Create link preview positioned below message text
247
+ * @param {string} [url]
248
+ * @param {object} [options]
249
+ * @returns {LinkPreview}
250
+ */
251
+ static below(url, options = {}) {
252
+ const lp = new LinkPreview({ show_above_text: false, ...options });
253
+ if (url) lp.url(url);
254
+ return lp;
255
+ }
256
+ }
package/lib/markdownv2.js CHANGED
@@ -26,4 +26,7 @@ export const mdv2 = {
26
26
  code: (text) => `\`${text.replace(/`/g, '\\`')}\``,
27
27
  pre: (text, language = '') => `\`\`\`${language}\n${text}\n\`\`\``,
28
28
  link: (text, url) => `[${escapeMarkdownV2(text)}](${url})`,
29
+ quote: (text) => text.split('\n').map((line) => `>${escapeMarkdownV2(line)}`).join('\n'),
30
+ expandableQuote: (text) => `**>${escapeMarkdownV2(text)}||`,
31
+ collapsibleQuote: (text) => `**>${escapeMarkdownV2(text)}||`,
29
32
  };
package/lib/markup.js CHANGED
@@ -170,22 +170,134 @@ export class Markup {
170
170
  /**
171
171
  * Standard text button for reply keyboard
172
172
  * @param {string} text
173
+ * @param {object} [options]
173
174
  */
174
- text: (text) => ({ text }),
175
+ text: (text, options = {}) => ({ text, ...options }),
175
176
 
176
177
  /**
177
178
  * Inline callback button
178
179
  * @param {string} text
179
- * @param {string} data
180
+ * @param {string|number} data
181
+ * @param {object} [options]
180
182
  */
181
- callback: (text, data) => ({ text, callback_data: String(data) }),
183
+ callback: (text, data, options = {}) => ({ text, callback_data: String(data), ...options }),
182
184
 
183
185
  /**
184
186
  * Inline URL button
185
187
  * @param {string} text
186
188
  * @param {string} url
189
+ * @param {object} [options]
190
+ */
191
+ url: (text, url, options = {}) => ({ text, url, ...options }),
192
+
193
+ /**
194
+ * Primary colored button (Blue / Main Action - Bot API 9.4+)
195
+ * @param {string} text
196
+ * @param {string|number|object} [dataOrUrl]
197
+ * @param {object} [options]
198
+ */
199
+ primary: (text, dataOrUrl, options = {}) => {
200
+ let base = {};
201
+ if (typeof dataOrUrl === 'string') {
202
+ if (/^(https?:\/\/|tg:\/\/)/i.test(dataOrUrl)) {
203
+ base = { url: dataOrUrl };
204
+ } else {
205
+ base = { callback_data: dataOrUrl };
206
+ }
207
+ } else if (typeof dataOrUrl === 'number') {
208
+ base = { callback_data: String(dataOrUrl) };
209
+ } else if (typeof dataOrUrl === 'object' && dataOrUrl !== null) {
210
+ base = dataOrUrl;
211
+ }
212
+ return {
213
+ text,
214
+ style: 'primary',
215
+ ...base,
216
+ ...options,
217
+ };
218
+ },
219
+
220
+ /**
221
+ * Danger colored button (Red / Destructive Action - Bot API 9.4+)
222
+ * @param {string} text
223
+ * @param {string|number|object} [dataOrUrl]
224
+ * @param {object} [options]
225
+ */
226
+ danger: (text, dataOrUrl, options = {}) => {
227
+ let base = {};
228
+ if (typeof dataOrUrl === 'string') {
229
+ if (/^(https?:\/\/|tg:\/\/)/i.test(dataOrUrl)) {
230
+ base = { url: dataOrUrl };
231
+ } else {
232
+ base = { callback_data: dataOrUrl };
233
+ }
234
+ } else if (typeof dataOrUrl === 'number') {
235
+ base = { callback_data: String(dataOrUrl) };
236
+ } else if (typeof dataOrUrl === 'object' && dataOrUrl !== null) {
237
+ base = dataOrUrl;
238
+ }
239
+ return {
240
+ text,
241
+ style: 'danger',
242
+ ...base,
243
+ ...options,
244
+ };
245
+ },
246
+
247
+ /**
248
+ * Success colored button (Green / Positive Action - Bot API 9.4+)
249
+ * @param {string} text
250
+ * @param {string|number|object} [dataOrUrl]
251
+ * @param {object} [options]
252
+ */
253
+ success: (text, dataOrUrl, options = {}) => {
254
+ let base = {};
255
+ if (typeof dataOrUrl === 'string') {
256
+ if (/^(https?:\/\/|tg:\/\/)/i.test(dataOrUrl)) {
257
+ base = { url: dataOrUrl };
258
+ } else {
259
+ base = { callback_data: dataOrUrl };
260
+ }
261
+ } else if (typeof dataOrUrl === 'number') {
262
+ base = { callback_data: String(dataOrUrl) };
263
+ } else if (typeof dataOrUrl === 'object' && dataOrUrl !== null) {
264
+ base = dataOrUrl;
265
+ }
266
+ return {
267
+ text,
268
+ style: 'success',
269
+ ...base,
270
+ ...options,
271
+ };
272
+ },
273
+
274
+ /**
275
+ * Generic colored button helper (Bot API 9.4+)
276
+ * @param {string} text
277
+ * @param {'primary'|'danger'|'success'} style
278
+ * @param {string|number|object} [dataOrUrl]
279
+ * @param {object} [options]
187
280
  */
188
- url: (text, url) => ({ text, url }),
281
+ colored: (text, style, dataOrUrl, options = {}) => {
282
+ let base = {};
283
+ if (typeof dataOrUrl === 'string') {
284
+ if (/^(https?:\/\/|tg:\/\/)/i.test(dataOrUrl)) {
285
+ base = { url: dataOrUrl };
286
+ } else {
287
+ base = { callback_data: dataOrUrl };
288
+ }
289
+ } else if (typeof dataOrUrl === 'number') {
290
+ base = { callback_data: String(dataOrUrl) };
291
+ } else if (typeof dataOrUrl === 'object' && dataOrUrl !== null) {
292
+ base = dataOrUrl;
293
+ }
294
+ return {
295
+ text,
296
+ style,
297
+ ...base,
298
+ ...options,
299
+ };
300
+ },
189
301
 
190
302
  /**
191
303
  * Web App button
package/lib/rich.js CHANGED
@@ -171,6 +171,15 @@ export class RichMessageBuilder {
171
171
  return this.quote(text, true);
172
172
  }
173
173
 
174
+ /**
175
+ * Add a collapsible / expandable blockquote (alias)
176
+ * @param {string} text
177
+ * @returns {this}
178
+ */
179
+ collapsibleQuote(text) {
180
+ return this.quote(text, true);
181
+ }
182
+
174
183
  /**
175
184
  * Add spoiler block
176
185
  * @param {string} text
@@ -370,6 +379,51 @@ export class RichMessageBuilder {
370
379
  return this.button(Markup.button.url(text, url));
371
380
  }
372
381
 
382
+ /**
383
+ * Add primary colored button (Blue - Bot API 9.4+)
384
+ * @param {string} text
385
+ * @param {string|number|object} dataOrUrl
386
+ * @param {object} [options]
387
+ * @returns {this}
388
+ */
389
+ primary(text, dataOrUrl, options = {}) {
390
+ return this.button(Markup.button.primary(text, dataOrUrl, options));
391
+ }
392
+
393
+ /**
394
+ * Add danger colored button (Red - Bot API 9.4+)
395
+ * @param {string} text
396
+ * @param {string|number|object} dataOrUrl
397
+ * @param {object} [options]
398
+ * @returns {this}
399
+ */
400
+ danger(text, dataOrUrl, options = {}) {
401
+ return this.button(Markup.button.danger(text, dataOrUrl, options));
402
+ }
403
+
404
+ /**
405
+ * Add success colored button (Green - Bot API 9.4+)
406
+ * @param {string} text
407
+ * @param {string|number|object} dataOrUrl
408
+ * @param {object} [options]
409
+ * @returns {this}
410
+ */
411
+ success(text, dataOrUrl, options = {}) {
412
+ return this.button(Markup.button.success(text, dataOrUrl, options));
413
+ }
414
+
415
+ /**
416
+ * Add generic colored button (Bot API 9.4+)
417
+ * @param {string} text
418
+ * @param {'primary'|'danger'|'success'} style
419
+ * @param {string|number|object} dataOrUrl
420
+ * @param {object} [options]
421
+ * @returns {this}
422
+ */
423
+ colored(text, style, dataOrUrl, options = {}) {
424
+ return this.button(Markup.button.colored(text, style, dataOrUrl, options));
425
+ }
426
+
373
427
  /**
374
428
  * Add Bot API 10.3 disabled button
375
429
  * @param {string} text