@open-discord-bots/framework 0.2.17 → 0.3.0

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.
Files changed (49) hide show
  1. package/dist/api/index.d.ts +16 -15
  2. package/dist/api/index.js +16 -15
  3. package/dist/api/main.d.ts +31 -23
  4. package/dist/api/main.js +3 -1
  5. package/dist/api/modules/action.d.ts +2 -2
  6. package/dist/api/modules/action.js +1 -5
  7. package/dist/api/modules/base.d.ts +2 -2
  8. package/dist/api/modules/builder.d.ts +2 -2
  9. package/dist/api/modules/builder.js +0 -4
  10. package/dist/api/modules/checker.d.ts +2 -2
  11. package/dist/api/modules/checker.js +2 -6
  12. package/dist/api/modules/component.d.ts +922 -0
  13. package/dist/api/modules/component.js +1344 -0
  14. package/dist/api/modules/config.d.ts +30 -1
  15. package/dist/api/modules/config.js +81 -0
  16. package/dist/api/modules/cooldown.d.ts +5 -5
  17. package/dist/api/modules/cooldown.js +1 -17
  18. package/dist/api/modules/database.d.ts +21 -13
  19. package/dist/api/modules/database.js +0 -23
  20. package/dist/api/modules/helpmenu.d.ts +9 -7
  21. package/dist/api/modules/helpmenu.js +22 -17
  22. package/dist/api/modules/language.d.ts +2 -2
  23. package/dist/api/modules/language.js +3 -7
  24. package/dist/api/modules/progressbar.d.ts +2 -1
  25. package/dist/api/modules/progressbar.js +1 -1
  26. package/dist/api/modules/responder.d.ts +2 -2
  27. package/dist/api/modules/responder.js +0 -4
  28. package/dist/api/modules/session.d.ts +1 -1
  29. package/dist/api/modules/session.js +1 -1
  30. package/dist/api/modules/startscreen.d.ts +2 -2
  31. package/dist/api/modules/startscreen.js +5 -3
  32. package/package.json +3 -2
  33. package/src/api/index.ts +16 -15
  34. package/src/api/main.ts +33 -24
  35. package/src/api/modules/action.ts +2 -4
  36. package/src/api/modules/base.ts +2 -2
  37. package/src/api/modules/builder.ts +2 -4
  38. package/src/api/modules/checker.ts +5 -6
  39. package/src/api/modules/component.ts +1822 -0
  40. package/src/api/modules/config.ts +78 -1
  41. package/src/api/modules/cooldown.ts +8 -13
  42. package/src/api/modules/database.ts +24 -32
  43. package/src/api/modules/helpmenu.ts +29 -22
  44. package/src/api/modules/language.ts +5 -7
  45. package/src/api/modules/progressbar.ts +2 -3
  46. package/src/api/modules/responder.ts +2 -4
  47. package/src/api/modules/session.ts +1 -1
  48. package/src/api/modules/startscreen.ts +6 -4
  49. package/src/api/modules/component.txt +0 -350
@@ -0,0 +1,1344 @@
1
+ ///////////////////////////////////////
2
+ //COMPONENTS MODULE
3
+ ///////////////////////////////////////
4
+ import { ODId, ODSystemError, ODManagerData, ODManager } from "./base.js";
5
+ import * as discord from "discord.js";
6
+ import { ODWorkerManager, ODWorker } from "./worker.js";
7
+ /**## ODComponentFactoryInstance `class`
8
+ * An Open Discord component factory instance.
9
+ *
10
+ * It will contain the final root component which is returned by an `ODComponentFactory`.
11
+ * This component can be used in another `ODComponentFactory` or rendered to a message/modal.
12
+ */
13
+ export class ODComponentFactoryInstance {
14
+ /**The root component of this factory. */
15
+ #rootComponent = null;
16
+ /**The root component of this factory. */
17
+ getComponent() {
18
+ return this.#rootComponent;
19
+ }
20
+ /**Set the root component of this factory. */
21
+ setComponent(c) {
22
+ this.#rootComponent = c;
23
+ }
24
+ }
25
+ /**## ODComponentFactory `class`
26
+ * An Open Discord component factory.
27
+ *
28
+ * It is a collection of functions/workers/hooks which will build a Discord message/modal component from scratch.
29
+ * Plugins can intercept and modify these workers to replace default behaviour or layout.
30
+ */
31
+ export class ODComponentFactory extends ODManagerData {
32
+ /**A collection of all workers for this component factory. */
33
+ workers;
34
+ constructor(id, callback, priority, callbackId) {
35
+ super(id);
36
+ this.workers = new ODWorkerManager("ascending");
37
+ if (callback)
38
+ this.workers.add(new ODWorker(callbackId ? callbackId : id, priority ?? 0, callback));
39
+ }
40
+ /**Run all workers and return the resulting component. */
41
+ async build(origin, params) {
42
+ const instance = new ODComponentFactoryInstance();
43
+ await this.workers.executeWorkers(instance, origin, params);
44
+ const rootComponent = instance.getComponent();
45
+ if (!rootComponent)
46
+ throw new ODSystemError("ODComponentFactory.build() --> Failed to build component! (id: " + this.id.value + ")");
47
+ return rootComponent.build();
48
+ }
49
+ }
50
+ /**## ODBaseComponentManager `class`
51
+ * A generic Open Discord component manager.
52
+ *
53
+ * It contains a collection of all Open Discord component factories. You can:
54
+ * - Add your own message/modal component factories
55
+ * - Modify existing message/modal component factories
56
+ *
57
+ * Messages created using this system are not compatible with `ODBuilder` messages!
58
+ */
59
+ export class ODBaseComponentManager extends ODManager {
60
+ get(id) {
61
+ return super.get(id);
62
+ }
63
+ remove(id) {
64
+ return super.remove(id);
65
+ }
66
+ exists(id) {
67
+ return super.exists(id);
68
+ }
69
+ }
70
+ /**## ODSharedComponentManager `class
71
+ * A special class with types for shared message/modal `ODComponent`'s.
72
+ * Create button, dropdown or any other layout component template to use them in messages & modals.
73
+ */
74
+ export class ODSharedComponentManager extends ODBaseComponentManager {
75
+ constructor(debug) {
76
+ super(debug, "shared component");
77
+ }
78
+ }
79
+ /**## ODMessageComponentManager `class
80
+ * A special class with types for `ODMessageComponent`'s.
81
+ * Create message templates to use as replies and make use of shared components.
82
+ */
83
+ export class ODMessageComponentManager extends ODBaseComponentManager {
84
+ constructor(debug) {
85
+ super(debug, "message component");
86
+ }
87
+ }
88
+ /**## ODModalComponentManager `class
89
+ * A special class with types for `ODModalComponent`'s.
90
+ * Create modal templates to use as forms and make use of shared components.
91
+ */
92
+ export class ODModalComponentManager extends ODBaseComponentManager {
93
+ constructor(debug) {
94
+ super(debug, "modal component");
95
+ }
96
+ }
97
+ /**## ODComponentManager `class`
98
+ * An Open Discord component manager.
99
+ *
100
+ * Create message & modal templates, re-use components and design all visual elements of the bot.
101
+ *
102
+ * Using the Open Discord component system has many advantages compared to vanilla `discord.js`:
103
+ * - Plugins can extend, edit & replace messages & components
104
+ * - Includes automatic error handling
105
+ * - Independent workers/hooks (with priority)
106
+ * - Fail-safe design using try-catch
107
+ * - Automatic switch between components v2 and legacy components depending on message requirements
108
+ * - Get to know the origin of the request (e.g. button, dropdown, modal, ...)
109
+ * - And so much more!
110
+ */
111
+ export class ODComponentManager {
112
+ /**The manager for all shared components. */
113
+ shared;
114
+ /**The manager for all messages components. */
115
+ messages;
116
+ /**The manager for all modals components. */
117
+ modals;
118
+ constructor(debug) {
119
+ this.shared = new ODSharedComponentManager(debug);
120
+ this.messages = new ODMessageComponentManager(debug);
121
+ this.modals = new ODModalComponentManager(debug);
122
+ }
123
+ }
124
+ /**## ODComponent `class`
125
+ * An Open Discord message/modal component.
126
+ *
127
+ * This class itself doesn't do anything, but is a blueprint for other
128
+ * `ODComponent` classes which represent the new Discord message/modal components.
129
+ */
130
+ export class ODComponent {
131
+ /**The id of this message/modal component. */
132
+ id;
133
+ /**The data or configuration of this message/modal component. */
134
+ data;
135
+ constructor(id, data) {
136
+ this.id = new ODId(id);
137
+ this.data = data;
138
+ }
139
+ }
140
+ /**## ODGroupComponent `class`
141
+ * An Open Discord message/modal component with children.
142
+ *
143
+ * This class itself doesn't do anything, but is a blueprint for other
144
+ * `ODGroupComponent` classes which represent the new Discord message/modal components.
145
+ */
146
+ export class ODGroupComponent extends ODComponent {
147
+ /**The collection of child components. */
148
+ children = [];
149
+ addComponent(c, mode = "start", reference) {
150
+ if (mode == "start")
151
+ this.children.unshift(c);
152
+ else if (mode == "end")
153
+ this.children.push(c);
154
+ else if (mode == "before") {
155
+ if (!reference || !this.children.find((c) => c.id.value === new ODId(reference).value))
156
+ this.children.unshift(c);
157
+ else {
158
+ const referenceIndex = this.children.findIndex((c) => c.id.value === new ODId(reference).value);
159
+ this.children.splice(referenceIndex, 0, c); //insert at position 'referenceIndex' (before)
160
+ }
161
+ }
162
+ else if (mode == "after") {
163
+ if (!reference || !this.children.find((c) => c.id.value === new ODId(reference).value))
164
+ this.children.push(c);
165
+ else {
166
+ const referenceIndex = this.children.findIndex((c) => c.id.value === new ODId(reference).value);
167
+ this.children.splice(referenceIndex + 1, 0, c); //insert at position 'referenceIndex+1' (after)
168
+ }
169
+ }
170
+ else if (mode == "index") {
171
+ if (!reference || typeof reference !== "number")
172
+ this.children.push(c);
173
+ else {
174
+ this.children.splice(reference, 0, c); //insert at position 'reference'
175
+ }
176
+ }
177
+ }
178
+ /**Get a component with a certain ID in this group. Returns `null` if non-existent. */
179
+ getComponent(id) {
180
+ const component = this.children.find((c) => c.id.value === new ODId(id).value);
181
+ return component ?? null;
182
+ }
183
+ /**Get the position of a component with a certain ID in this group. Returns `-1` if non-existent. */
184
+ getComponentPosition(id) {
185
+ return this.children.findIndex((c) => c.id.value === new ODId(id).value);
186
+ }
187
+ /**Returns if a component with a certain ID exists in this group. */
188
+ existsComponent(id) {
189
+ const component = this.children.find((c) => c.id.value === new ODId(id).value);
190
+ return component ? true : false;
191
+ }
192
+ /**Remove a component with a certain ID from this group. Returns the removed component or `null if non-existent. */
193
+ removeComponent(id) {
194
+ const index = this.children.findIndex((c) => c.id.value === new ODId(id).value);
195
+ if (index < 0)
196
+ return null;
197
+ else
198
+ return this.children.splice(index, 1)[0];
199
+ }
200
+ moveComponent(id, mode = "start", reference) {
201
+ const component = this.removeComponent(id);
202
+ if (component) {
203
+ if (mode == "start" || mode == "end")
204
+ this.addComponent(component, mode);
205
+ if ((mode == "before" || mode == "after") && reference)
206
+ this.addComponent(component, mode, reference);
207
+ if (mode == "index" && typeof reference == "number")
208
+ this.addComponent(component, mode, reference);
209
+ return;
210
+ }
211
+ }
212
+ }
213
+ /**## ODParentComponent `class`
214
+ * An Open Discord message/modal component with a single child.
215
+ *
216
+ * This class itself doesn't do anything, but is a blueprint for other
217
+ * `ODParentComponent` classes which represent the new Discord message/modal components.
218
+ */
219
+ export class ODParentComponent extends ODComponent {
220
+ /**The child component of this parent. */
221
+ #child = null;
222
+ /**The child component of this parent. */
223
+ get child() {
224
+ return this.#child;
225
+ }
226
+ /**Set the child component of this parent. */
227
+ setComponent(c) {
228
+ this.#child = c;
229
+ }
230
+ }
231
+ /**## ODMessageComponent `class`
232
+ * A message builder with **components v2** support.
233
+ * Add items to this message using `addComponent()`.
234
+ *
235
+ * Use `ODSimpleMessageComponent` for components v1, polls, embeds, etc
236
+ */
237
+ export class ODMessageComponent extends ODGroupComponent {
238
+ constructor(id, data) {
239
+ const initData = { ...data };
240
+ super(id, initData);
241
+ }
242
+ async build() {
243
+ if (this.children.length < 1)
244
+ throw new ODSystemError("ODMessageComponent:build('" + this.id.value + "') => Requires at least one child component.");
245
+ const attachments = [...(this.data.additionalAttachments ?? [])];
246
+ const components = [];
247
+ for (const component of this.children) {
248
+ if (component instanceof ODFileComponent) {
249
+ //ODFileComponent (special)
250
+ const res = await component.build();
251
+ if (res)
252
+ components.push(res.file);
253
+ if (res?.attachment)
254
+ attachments.push(res.attachment);
255
+ }
256
+ else if (component instanceof ODGalleryComponent) {
257
+ //ODGalleryComponent (special)
258
+ const res = await component.build();
259
+ if (res)
260
+ components.push(res.gallery);
261
+ if (res?.attachments)
262
+ attachments.push(...res.attachments);
263
+ }
264
+ else {
265
+ //general ODComponent's
266
+ const res = await component.build();
267
+ if (res)
268
+ components.push(res);
269
+ }
270
+ }
271
+ return {
272
+ msg: {
273
+ components,
274
+ files: attachments,
275
+ ...this.data.additionalOptions
276
+ },
277
+ componentsV2: true,
278
+ ephemeral: this.data.ephemeral ?? false,
279
+ supressEmbeds: this.data.supressEmbeds ?? false,
280
+ supressNotifications: this.data.supressNotifications ?? false
281
+ };
282
+ }
283
+ /**Enable/disable ephemeral mode. */
284
+ setEphemeral(value) {
285
+ this.data.ephemeral = value;
286
+ }
287
+ /**Enable supress (hide) embeds mode. */
288
+ setSupressEmbeds(value) {
289
+ this.data.supressEmbeds = value;
290
+ }
291
+ /**Enable supress (hide) notifications mode. */
292
+ setSupressNotifications(value) {
293
+ this.data.supressNotifications = value;
294
+ }
295
+ /**Add an additional attachment which can be used in components as `attachment://...` */
296
+ addAdditionalAttachments(...attachments) {
297
+ if (!this.data.additionalAttachments)
298
+ this.data.additionalAttachments = [];
299
+ this.data.additionalAttachments.push(...attachments);
300
+ }
301
+ }
302
+ /**## ODSimpleMessageComponent `class`
303
+ * A message builder with **components v1** support.
304
+ * Add items to this message using `addComponent()`.
305
+ *
306
+ * Use `ODMessageComponent` for components v2, components, containers, etc
307
+ */
308
+ export class ODSimpleMessageComponent extends ODGroupComponent {
309
+ constructor(id, data) {
310
+ const initData = { ...data };
311
+ super(id, initData);
312
+ }
313
+ async build() {
314
+ if (this.children.length < 1)
315
+ throw new ODSystemError("ODMessageComponent:build('" + this.id.value + "') => Requires at least one child component.");
316
+ const attachments = [...(this.data.additionalAttachments ?? [])];
317
+ const embeds = [];
318
+ let content = undefined;
319
+ let poll = undefined;
320
+ for (const component of this.children) {
321
+ if (component instanceof ODFileComponent) {
322
+ //ODFileComponent (special)
323
+ const res = await component.build();
324
+ if (res?.attachment)
325
+ attachments.push(res.attachment);
326
+ }
327
+ else if (component instanceof ODContentComponent) {
328
+ //ODContentComponent (special)
329
+ const res = await component.build();
330
+ if (res)
331
+ content = res.content;
332
+ }
333
+ else if (component instanceof ODEmbedComponent) {
334
+ //ODEmbedComponent (special)
335
+ const res = await component.build();
336
+ if (res)
337
+ embeds.push(res);
338
+ }
339
+ else {
340
+ //ODPollComponent (special)
341
+ const res = await component.build();
342
+ if (res)
343
+ poll = res;
344
+ }
345
+ }
346
+ return {
347
+ msg: {
348
+ content,
349
+ embeds,
350
+ poll,
351
+ files: attachments,
352
+ ...this.data.additionalOptions
353
+ },
354
+ componentsV2: false,
355
+ ephemeral: this.data.ephemeral ?? false,
356
+ supressEmbeds: this.data.supressEmbeds ?? false,
357
+ supressNotifications: this.data.supressNotifications ?? false
358
+ };
359
+ }
360
+ /**Enable/disable ephemeral mode. */
361
+ setEphemeral(value) {
362
+ this.data.ephemeral = value;
363
+ }
364
+ /**Enable supress (hide) embeds mode. */
365
+ setSupressEmbeds(value) {
366
+ this.data.supressEmbeds = value;
367
+ }
368
+ /**Enable supress (hide) notifications mode. */
369
+ setSupressNotifications(value) {
370
+ this.data.supressNotifications = value;
371
+ }
372
+ /**Add an additional attachment which can be used in components as `attachment://...` */
373
+ addAdditionalAttachments(...attachments) {
374
+ if (!this.data.additionalAttachments)
375
+ this.data.additionalAttachments = [];
376
+ this.data.additionalAttachments.push(...attachments);
377
+ }
378
+ }
379
+ /**## ODModalComponent `class`
380
+ * A modal builder with **components v2** support.
381
+ * Add questions, select menu's & labels to this modal using `addComponent()`.
382
+ */
383
+ export class ODModalComponent extends ODGroupComponent {
384
+ constructor(id, data) {
385
+ const initData = { title: "<empty>", ...data };
386
+ super(id, initData);
387
+ }
388
+ async build() {
389
+ if (this.children.length < 1)
390
+ throw new ODSystemError("ODModalComponent:build('" + this.id.value + "') => Requires at least one child component.");
391
+ if (this.children.length > 5)
392
+ throw new ODSystemError("ODModalComponent:build('" + this.id.value + "') => A modal doesn't support more than 5 components.");
393
+ const components = [];
394
+ for (const component of this.children) {
395
+ if (component instanceof ODLabelComponent) {
396
+ //ODLabelComponent (special)
397
+ const res = await component.build();
398
+ if (res)
399
+ components.push(res.toJSON());
400
+ }
401
+ else {
402
+ //ODTextComponent (special)
403
+ const res = await component.build();
404
+ if (res)
405
+ components.push(res.toJSON());
406
+ }
407
+ }
408
+ return new discord.ModalBuilder({
409
+ components,
410
+ title: this.data.title,
411
+ customId: this.data.customId
412
+ });
413
+ }
414
+ /**Set the title of the modal. */
415
+ setTitle(title) {
416
+ this.data.title = title;
417
+ }
418
+ /**Set the custom id of this modal. */
419
+ setCustomId(id) {
420
+ this.data.customId = id ?? undefined;
421
+ return this;
422
+ }
423
+ }
424
+ /**## ODActionRowComponent `class`
425
+ * An actionrow component which is a container for buttons, a select menu or inputs in a message or modal.
426
+ */
427
+ export class ODActionRowComponent extends ODGroupComponent {
428
+ constructor(id, data) {
429
+ const initData = { ...data };
430
+ super(id, initData);
431
+ }
432
+ async build() {
433
+ if (this.children.length < 1)
434
+ throw new ODSystemError("ODActionRowComponent:build('" + this.id.value + "') => Requires at least one child component.");
435
+ if (this.children.length > 5)
436
+ throw new ODSystemError("ODActionRowComponent:build('" + this.id.value + "') => An action row doesn't support more than 5 components.");
437
+ const components = [];
438
+ for (const component of this.children) {
439
+ //actionrow ODComponent's
440
+ const res = await component.build();
441
+ if (res)
442
+ components.push(res);
443
+ }
444
+ return new discord.ActionRowBuilder({ components });
445
+ }
446
+ }
447
+ /**## ODContainerComponent `class`
448
+ * An embed-like container for text, titles, buttons, sections, separators and other components.
449
+ */
450
+ export class ODContainerComponent extends ODGroupComponent {
451
+ constructor(id, data) {
452
+ const initData = { spoiler: false, ...data };
453
+ super(id, initData);
454
+ }
455
+ async build() {
456
+ if (this.children.length < 1)
457
+ throw new ODSystemError("ODContainerComponent:build('" + this.id.value + "') => Requires at least one child component.");
458
+ const components = [];
459
+ const attachments = [];
460
+ for (const component of this.children) {
461
+ if (component instanceof ODFileComponent) {
462
+ //ODFileComponent (special)
463
+ const res = await component.build();
464
+ if (res)
465
+ components.push(res.file.toJSON());
466
+ if (res?.attachment)
467
+ attachments.push(res.attachment);
468
+ }
469
+ else if (component instanceof ODGalleryComponent) {
470
+ //ODGalleryComponent (special)
471
+ const res = await component.build();
472
+ if (res)
473
+ components.push(res.gallery.toJSON());
474
+ if (res?.attachments)
475
+ attachments.push(...res.attachments);
476
+ }
477
+ else {
478
+ //general ODComponent's
479
+ const res = await component.build();
480
+ if (res)
481
+ components.push(res.toJSON());
482
+ }
483
+ }
484
+ return {
485
+ container: new discord.ContainerBuilder({
486
+ components,
487
+ accent_color: this.data.color ? discord.resolveColor(this.data.color) : undefined,
488
+ spoiler: this.data.spoiler
489
+ }),
490
+ attachments
491
+ };
492
+ }
493
+ /**Set the accent color of this embed-like container. */
494
+ setColor(color) {
495
+ this.data.color = color ?? undefined;
496
+ }
497
+ /**Mark the contents of this container as spoiler. */
498
+ setSpoiler(spoiler) {
499
+ this.data.spoiler = spoiler;
500
+ }
501
+ }
502
+ /**## ODSectionComponent `class`
503
+ * A layout component that allows you to contextually associate content with an accessory component.
504
+ * - Components: Left
505
+ * - Accessory: Right
506
+ */
507
+ export class ODSectionComponent extends ODGroupComponent {
508
+ constructor(id, data) {
509
+ const initData = { ...data };
510
+ super(id, initData);
511
+ }
512
+ async build() {
513
+ if (this.children.length < 1)
514
+ throw new ODSystemError("ODSectionComponent:build('" + this.id.value + "') => Requires at least one child component.");
515
+ if (this.children.length > 3)
516
+ throw new ODSystemError("ODSectionComponent:build('" + this.id.value + "') => A maximum of 3 child components are allowed in a section.");
517
+ const components = [];
518
+ for (const component of this.children) {
519
+ //section ODComponent's
520
+ const res = await component.build();
521
+ if (res)
522
+ components.push(res.toJSON());
523
+ }
524
+ let accessory = undefined;
525
+ if (this.data.accessory) {
526
+ const accessoryRes = await this.data.accessory.build();
527
+ if (accessoryRes)
528
+ accessory = accessoryRes.toJSON();
529
+ }
530
+ return new discord.SectionBuilder({ components, accessory });
531
+ }
532
+ /**Set the accessory component shown on the right side of the section. */
533
+ setAccessory(accessory) {
534
+ this.data.accessory = accessory ?? undefined;
535
+ }
536
+ }
537
+ /**## ODLabelComponent `class`
538
+ * A visual separator between components. The visibility and padding of this separator can be changed.
539
+ */
540
+ export class ODLabelComponent extends ODParentComponent {
541
+ constructor(id, data) {
542
+ const initData = { title: "<empty>", ...data };
543
+ super(id, initData);
544
+ }
545
+ async build() {
546
+ let component = undefined;
547
+ if (this.child) {
548
+ const accessoryRes = await this.child.build();
549
+ if (accessoryRes)
550
+ component = accessoryRes.toJSON();
551
+ }
552
+ return new discord.LabelBuilder({
553
+ label: this.data.title,
554
+ description: this.data.description,
555
+ component
556
+ });
557
+ }
558
+ /**Set the title of the child component in the modal. */
559
+ setTitle(title) {
560
+ this.data.title = title;
561
+ }
562
+ /**Set the description of the child component in the modal. */
563
+ setDescription(description) {
564
+ this.data.description = description ?? undefined;
565
+ }
566
+ }
567
+ /**## ODSeparatorComponent `class`
568
+ * A visual separator between components. The visibility and padding of this separator can be changed.
569
+ */
570
+ export class ODSeparatorComponent extends ODComponent {
571
+ constructor(id, data) {
572
+ const initData = { divider: true, spacing: "small", ...data };
573
+ super(id, initData);
574
+ }
575
+ async build() {
576
+ return new discord.SeparatorBuilder({
577
+ divider: this.data.divider,
578
+ spacing: (this.data.spacing == "small") ? discord.SeparatorSpacingSize.Small : discord.SeparatorSpacingSize.Large
579
+ });
580
+ }
581
+ /**Set whether a visual divider should be displayed in the component. (Default: `true`). */
582
+ setDivider(divider) {
583
+ this.data.divider = divider;
584
+ }
585
+ /**Set the size of separator padding (Default `small`). */
586
+ setSpacing(spacing) {
587
+ this.data.spacing = spacing;
588
+ }
589
+ }
590
+ /**## ODTextComponent `class`
591
+ * A text component which renders markdown text in a message.
592
+ */
593
+ export class ODTextComponent extends ODComponent {
594
+ constructor(id, data) {
595
+ const initData = { content: "", ...data };
596
+ super(id, initData);
597
+ }
598
+ async build() {
599
+ if (this.data.content.length < 1)
600
+ throw new ODSystemError("ODTextComponent:build('" + this.id.value + "') => Unable to display text component without contents.");
601
+ return new discord.TextDisplayBuilder({
602
+ content: this.data.content
603
+ });
604
+ }
605
+ /**Set the text to display. */
606
+ setContent(value) {
607
+ this.data.content = value;
608
+ }
609
+ }
610
+ /**## ODFileComponent `class`
611
+ * A file component which adds a file in a message.
612
+ */
613
+ export class ODFileComponent extends ODComponent {
614
+ constructor(id, data) {
615
+ const initData = { name: "file.txt", ...data };
616
+ super(id, initData);
617
+ }
618
+ async build() {
619
+ if (!this.data.content && !this.data.externalUrl)
620
+ throw new ODSystemError("ODFileComponent:build('" + this.id.value + "') => Unable to display file component without binary or url.");
621
+ const attachment = (this.data.content) ? new discord.AttachmentBuilder(this.data.content, {
622
+ name: this.data.name,
623
+ description: this.data.description
624
+ }) : null;
625
+ return {
626
+ attachment,
627
+ file: new discord.FileBuilder({
628
+ file: {
629
+ url: (this.data.externalUrl ?? "attachment://" + this.data.name)
630
+ },
631
+ spoiler: this.data.spoiler
632
+ })
633
+ };
634
+ }
635
+ /**Set the filename + extension. */
636
+ setName(value) {
637
+ this.data.name = value;
638
+ }
639
+ /**Set the file description. */
640
+ setDescription(value) {
641
+ this.data.description = value ?? undefined;
642
+ }
643
+ /**Set the text/binary contents of the file. */
644
+ setContent(value) {
645
+ this.data.content = value ?? undefined;
646
+ }
647
+ /**Set a URL to an external file or image. When used, `setContent()` will be ignored! */
648
+ setExternalUrl(value) {
649
+ this.data.externalUrl = value ?? undefined;
650
+ }
651
+ /**Mark the file as spoiler. */
652
+ setSpoiler(value) {
653
+ this.data.spoiler = value;
654
+ }
655
+ }
656
+ /**## ODGalleryComponent `class`
657
+ * A gallery component which renders a grid of media items (images/videos) in a message.
658
+ * Add items to this gallery using `addComponent()`.
659
+ */
660
+ export class ODGalleryComponent extends ODGroupComponent {
661
+ constructor(id, data) {
662
+ const initData = { ...data };
663
+ super(id, initData);
664
+ }
665
+ async build() {
666
+ if (this.children.length < 1)
667
+ throw new ODSystemError("ODGalleryComponent:build('" + this.id.value + "') => Requires at least one child component.");
668
+ const gallery = new discord.MediaGalleryBuilder();
669
+ const attachments = [];
670
+ for (const file of this.children) {
671
+ if (!file.data.content && !file.data.externalUrl)
672
+ continue;
673
+ if (file.data.content)
674
+ attachments.push(new discord.AttachmentBuilder(file.data.content, {
675
+ name: file.data.name,
676
+ description: file.data.description
677
+ }));
678
+ gallery.addItems(new discord.MediaGalleryItemBuilder({
679
+ description: file.data.description,
680
+ spoiler: file.data.spoiler,
681
+ media: {
682
+ url: (file.data.externalUrl ?? "attachment://" + file.data.name)
683
+ }
684
+ }));
685
+ }
686
+ return { gallery, attachments };
687
+ }
688
+ }
689
+ /**## ODThumbnailComponent `class`
690
+ * A thumbnail component which renders a small image as an accessory inside an `ODSectionComponent`.
691
+ * This component must be used via `ODSectionComponent.setComponent()`
692
+ */
693
+ export class ODThumbnailComponent extends ODComponent {
694
+ constructor(id, data) {
695
+ const initData = { url: "", ...data };
696
+ super(id, initData);
697
+ }
698
+ async build() {
699
+ if (this.data.url.length < 1)
700
+ throw new ODSystemError("ODThumbnailComponent:build('" + this.id.value + "') => Thumbnail component requires an image URL.");
701
+ return new discord.ThumbnailBuilder({
702
+ media: { url: this.data.url },
703
+ description: this.data.description,
704
+ spoiler: this.data.spoiler
705
+ });
706
+ }
707
+ /**Set the URL of the thumbnail image. */
708
+ setUrl(value) {
709
+ this.data.url = value;
710
+ }
711
+ /**Set the alt text/description of the thumbnail image. */
712
+ setDescription(value) {
713
+ this.data.description = value ?? undefined;
714
+ }
715
+ /**Mark the thumbnail as a spoiler. */
716
+ setSpoiler(value) {
717
+ this.data.spoiler = value;
718
+ }
719
+ }
720
+ /**## ODContentComponent `class`
721
+ * A text component which renders markdown text in a message without `Components V2` enabled. (Old behaviour)
722
+ */
723
+ export class ODContentComponent extends ODComponent {
724
+ constructor(id, data) {
725
+ const initData = { content: "", ...data };
726
+ super(id, initData);
727
+ }
728
+ async build() {
729
+ if (this.data.content.length < 1)
730
+ throw new ODSystemError("ODContentComponent:build('" + this.id.value + "') => Unable to display content component without contents.");
731
+ return {
732
+ content: this.data.content
733
+ };
734
+ }
735
+ /**Set the text to display. */
736
+ setContent(value) {
737
+ this.data.content = value;
738
+ }
739
+ }
740
+ /**## ODEmbedComponent `class`
741
+ * An embed component which renders an embed in a message without `Components V2` enabled. (Old behaviour)
742
+ */
743
+ export class ODEmbedComponent extends ODComponent {
744
+ constructor(id, data) {
745
+ const initData = { ...data };
746
+ super(id, initData);
747
+ }
748
+ async build() {
749
+ if (this.data.title && this.data.title.length > 256)
750
+ throw new ODSystemError("ODEmbedComponent:build('" + this.id.value + "') => An embed title can't exceed 256 characters.");
751
+ if (this.data.description && this.data.description.length > 4096)
752
+ throw new ODSystemError("ODEmbedComponent:build('" + this.id.value + "') => An embed description can't exceed 4096 characters.");
753
+ if (this.data.fields && this.data.fields.length > 25)
754
+ throw new ODSystemError("ODEmbedComponent:build('" + this.id.value + "') => An embed can't contain more than 25 fields.");
755
+ if (this.data.footerText && this.data.footerText.length > 2048)
756
+ throw new ODSystemError("ODEmbedComponent:build('" + this.id.value + "') => An embed footer can't exceed 2048 characters.");
757
+ if (this.data.authorText && this.data.authorText.length > 256)
758
+ throw new ODSystemError("ODEmbedComponent:build('" + this.id.value + "') => An embed author can't exceed 256 characters.");
759
+ return new discord.EmbedBuilder({
760
+ title: this.data.title,
761
+ color: (this.data.color) ? discord.resolveColor(this.data.color) : undefined,
762
+ url: this.data.url,
763
+ description: this.data.description,
764
+ author: (this.data.authorText) ? {
765
+ name: this.data.authorText,
766
+ icon_url: this.data.authorImage,
767
+ url: this.data.authorUrl
768
+ } : undefined,
769
+ footer: (this.data.footerText) ? {
770
+ text: this.data.footerText,
771
+ icon_url: this.data.footerImage
772
+ } : undefined,
773
+ image: (this.data.image) ? {
774
+ url: this.data.image
775
+ } : undefined,
776
+ thumbnail: (this.data.thumbnail) ? {
777
+ url: this.data.thumbnail
778
+ } : undefined,
779
+ fields: this.data.fields,
780
+ timestamp: (this.data.timestamp) ? new Date(this.data.timestamp).toISOString() : undefined
781
+ });
782
+ }
783
+ /**Set the title of this embed */
784
+ setTitle(title) {
785
+ this.data.title = title ?? undefined;
786
+ return this;
787
+ }
788
+ /**Set the color of this embed */
789
+ setColor(color) {
790
+ this.data.color = color ?? undefined;
791
+ return this;
792
+ }
793
+ /**Set the url of this embed */
794
+ setUrl(url) {
795
+ this.data.url = url ?? undefined;
796
+ return this;
797
+ }
798
+ /**Set the description of this embed */
799
+ setDescription(description) {
800
+ this.data.description = description ?? undefined;
801
+ return this;
802
+ }
803
+ /**Set the author of this embed */
804
+ setAuthor(text, image, url) {
805
+ this.data.authorText = text ?? undefined;
806
+ this.data.authorImage = image ?? undefined;
807
+ this.data.authorUrl = url ?? undefined;
808
+ return this;
809
+ }
810
+ /**Set the footer of this embed */
811
+ setFooter(text, image) {
812
+ this.data.footerText = text ?? undefined;
813
+ this.data.footerImage = image ?? undefined;
814
+ return this;
815
+ }
816
+ /**Set the image of this embed */
817
+ setImage(image) {
818
+ this.data.image = image ?? undefined;
819
+ return this;
820
+ }
821
+ /**Set the thumbnail of this embed */
822
+ setThumbnail(thumbnail) {
823
+ this.data.thumbnail = thumbnail ?? undefined;
824
+ return this;
825
+ }
826
+ /**Set the fields of this embed */
827
+ setFields(fields) {
828
+ //Check field properties
829
+ for (const [index, field] of fields.entries()) {
830
+ if (field.value.length >= 1024)
831
+ throw new ODSystemError("ODEmbedComponent:build('" + this.id.value + "') => field " + index + " reached 1024 character limit!");
832
+ if (field.name.length >= 256)
833
+ throw new ODSystemError("ODEmbedComponent:build('" + this.id.value + "') => field " + index + " reached 256 name character limit!");
834
+ }
835
+ this.data.fields = fields;
836
+ return this;
837
+ }
838
+ /**Add fields to this embed */
839
+ addFields(...fields) {
840
+ //Check field properties
841
+ for (const [index, field] of fields.entries()) {
842
+ if (field.value.length >= 1024)
843
+ throw new ODSystemError("ODEmbedComponent:build('" + this.id.value + "') => field " + index + " reached 1024 character limit!");
844
+ if (field.name.length >= 256)
845
+ throw new ODSystemError("ODEmbedComponent:build('" + this.id.value + "') => field " + index + " reached 256 name character limit!");
846
+ }
847
+ if (!this.data.fields)
848
+ this.data.fields = [];
849
+ this.data.fields.push(...fields);
850
+ return this;
851
+ }
852
+ /**Clear all fields from this embed */
853
+ clearFields() {
854
+ this.data.fields = [];
855
+ return this;
856
+ }
857
+ /**Set the timestamp of this embed. When set to `true`, the current timestamp is used. */
858
+ setTimestamp(timestamp) {
859
+ if (timestamp === true)
860
+ this.data.timestamp = new Date();
861
+ else
862
+ this.data.timestamp = timestamp ?? undefined;
863
+ return this;
864
+ }
865
+ }
866
+ /**## ODPollComponent `class`
867
+ * A poll component which adds a poll to a message without `Components V2` enabled. (Old behaviour)
868
+ */
869
+ export class ODPollComponent extends ODComponent {
870
+ constructor(id, data) {
871
+ const initData = { question: "<empty>", durationHours: 1, allowMultiSelect: false, answers: [], ...data };
872
+ super(id, initData);
873
+ }
874
+ async build() {
875
+ if (this.data.question.length < 1)
876
+ throw new ODSystemError("ODPollComponent:build('" + this.id.value + "') => Please provide a valid poll question.");
877
+ if (this.data.answers.length < 1)
878
+ throw new ODSystemError("ODPollComponent:build('" + this.id.value + "') => Please provide at least one answer to the poll.");
879
+ return {
880
+ layoutType: discord.PollLayoutType.Default,
881
+ allowMultiselect: this.data.allowMultiSelect,
882
+ duration: this.data.durationHours,
883
+ question: { text: this.data.question },
884
+ answers: this.data.answers
885
+ };
886
+ }
887
+ /**Set the poll question. */
888
+ setQuestion(question) {
889
+ this.data.question = question;
890
+ }
891
+ /**Set the poll duration in hours. */
892
+ setDurationHours(duration) {
893
+ this.data.durationHours = duration;
894
+ }
895
+ /**Allow selecting multiple answers. */
896
+ setMultiSelect(multi) {
897
+ this.data.allowMultiSelect = multi;
898
+ }
899
+ /**Set the poll answers. */
900
+ setAnswers(answers) {
901
+ this.data.answers = answers;
902
+ }
903
+ /**Add additional poll answers. */
904
+ addAnswers(...answers) {
905
+ this.data.answers.push(...answers);
906
+ }
907
+ }
908
+ /**## ODButtonComponent `class`
909
+ * A button component which renders an interactive button inside the message.
910
+ * A reply can be sent using Open Discord responders.
911
+ */
912
+ export class ODButtonComponent extends ODComponent {
913
+ constructor(id, data) {
914
+ const initData = { color: "gray", disabled: false, ...data };
915
+ super(id, initData);
916
+ }
917
+ async build() {
918
+ if (!this.data.emoji && !this.data.label)
919
+ throw new ODSystemError("ODButtonComponent:build('" + this.id.value + "') => A button must include at least one label or emoji.");
920
+ if (this.data.customId && this.data.customId.length > 100)
921
+ throw new ODSystemError("ODButtonComponent:build('" + this.id.value + "') => A custom ID '" + this.data.customId + "' must be shorter than 100 characters.");
922
+ return new discord.ButtonBuilder({
923
+ customId: (!this.data.url) ? this.data.customId : undefined,
924
+ label: this.data.label,
925
+ emoji: this.data.emoji ? discord.resolvePartialEmoji(this.data.emoji) : undefined,
926
+ disabled: this.data.disabled,
927
+ url: (this.data.url) ? this.data.url : undefined,
928
+ style: this.getButtonStyle(),
929
+ });
930
+ }
931
+ /**Get the `discord.ButtonStyle` for the specified `ODValidButtonColor` */
932
+ getButtonStyle() {
933
+ if (this.data.url)
934
+ return discord.ButtonStyle.Link;
935
+ else if (this.data.color == "blue")
936
+ return discord.ButtonStyle.Primary;
937
+ else if (this.data.color == "green")
938
+ return discord.ButtonStyle.Success;
939
+ else if (this.data.color == "red")
940
+ return discord.ButtonStyle.Danger;
941
+ else
942
+ return discord.ButtonStyle.Secondary;
943
+ }
944
+ /**Set the custom id of this button. Ignored when `setUrl()` is used. */
945
+ setCustomId(id) {
946
+ this.data.customId = id ?? undefined;
947
+ return this;
948
+ }
949
+ /**Set the url of this button. */
950
+ setUrl(url) {
951
+ this.data.url = url ?? undefined;
952
+ return this;
953
+ }
954
+ /**Set the color of this button. Ignored when `setUrl()` is used. */
955
+ setColor(color) {
956
+ this.data.color = color;
957
+ return this;
958
+ }
959
+ /**Set the label of this button. */
960
+ setLabel(label) {
961
+ this.data.label = label ?? undefined;
962
+ return this;
963
+ }
964
+ /**Set the emoji of this button. */
965
+ setEmoji(emoji) {
966
+ this.data.emoji = emoji ?? undefined;
967
+ return this;
968
+ }
969
+ /**Disable this button. */
970
+ setDisabled(disabled) {
971
+ this.data.disabled = disabled;
972
+ return this;
973
+ }
974
+ }
975
+ /**## ODShortInputComponent `class`
976
+ * A short text input component for modals.
977
+ * It must be placed inside an `ODLabelComponent`.
978
+ */
979
+ export class ODShortInputComponent extends ODComponent {
980
+ constructor(id, data) {
981
+ const initData = { required: false, ...data };
982
+ super(id, initData);
983
+ }
984
+ async build() {
985
+ return new discord.TextInputBuilder({
986
+ style: discord.TextInputStyle.Short,
987
+ customId: this.data.customId,
988
+ minLength: this.data.minLength,
989
+ maxLength: this.data.maxLength,
990
+ required: this.data.required,
991
+ placeholder: this.data.placeholder,
992
+ value: this.data.initialValue
993
+ });
994
+ }
995
+ /**Set the custom id of this modal text input. */
996
+ setCustomId(id) {
997
+ this.data.customId = id ?? undefined;
998
+ return this;
999
+ }
1000
+ /**Set the minimum amount of characters of this modal text input. */
1001
+ setMinLength(length) {
1002
+ this.data.minLength = length ?? undefined;
1003
+ return this;
1004
+ }
1005
+ /**Set the maximum amount of characters of this modal text input. */
1006
+ setMaxLength(length) {
1007
+ this.data.maxLength = length ?? undefined;
1008
+ return this;
1009
+ }
1010
+ /**Set the placeholder of this modal text input. */
1011
+ setPlaceholder(placeholder) {
1012
+ this.data.placeholder = placeholder ?? undefined;
1013
+ return this;
1014
+ }
1015
+ /**Set the initial value of this modal text input. */
1016
+ setInitialValue(initialValue) {
1017
+ this.data.initialValue = initialValue ?? undefined;
1018
+ return this;
1019
+ }
1020
+ /**Mark this modal text input as required. */
1021
+ setRequired(required) {
1022
+ this.data.required = required;
1023
+ return this;
1024
+ }
1025
+ }
1026
+ /**## ODParagraphInputComponent `class`
1027
+ * A paragraph text input component for modals.
1028
+ * It must be placed inside an `ODLabelComponent`.
1029
+ */
1030
+ export class ODParagraphInputComponent extends ODComponent {
1031
+ constructor(id, data) {
1032
+ const initData = { required: false, ...data };
1033
+ super(id, initData);
1034
+ }
1035
+ async build() {
1036
+ return new discord.TextInputBuilder({
1037
+ style: discord.TextInputStyle.Paragraph,
1038
+ customId: this.data.customId,
1039
+ minLength: this.data.minLength,
1040
+ maxLength: this.data.maxLength,
1041
+ required: this.data.required,
1042
+ placeholder: this.data.placeholder,
1043
+ value: this.data.initialValue
1044
+ });
1045
+ }
1046
+ /**Set the custom id of this modal text input. */
1047
+ setCustomId(id) {
1048
+ this.data.customId = id ?? undefined;
1049
+ return this;
1050
+ }
1051
+ /**Set the minimum amount of characters of this modal text input. */
1052
+ setMinLength(length) {
1053
+ this.data.minLength = length ?? undefined;
1054
+ return this;
1055
+ }
1056
+ /**Set the maximum amount of characters of this modal text input. */
1057
+ setMaxLength(length) {
1058
+ this.data.maxLength = length ?? undefined;
1059
+ return this;
1060
+ }
1061
+ /**Set the placeholder of this modal text input. */
1062
+ setPlaceholder(placeholder) {
1063
+ this.data.placeholder = placeholder ?? undefined;
1064
+ return this;
1065
+ }
1066
+ /**Set the initial value of this modal text input. */
1067
+ setInitialValue(initialValue) {
1068
+ this.data.initialValue = initialValue ?? undefined;
1069
+ return this;
1070
+ }
1071
+ /**Mark this modal text input as required. */
1072
+ setRequired(required) {
1073
+ this.data.required = required;
1074
+ return this;
1075
+ }
1076
+ }
1077
+ /**## ODDropdownComponent `class`
1078
+ * A dropdown component which renders an interactive dropdown inside the message/modal.
1079
+ * A reply can be sent using Open Discord responders.
1080
+ */
1081
+ export class ODDropdownComponent extends ODComponent {
1082
+ constructor(id, data) {
1083
+ const initData = { type: "string", ...data };
1084
+ super(id, initData);
1085
+ }
1086
+ async build() {
1087
+ const genericOpts = {
1088
+ customId: this.data.customId,
1089
+ disabled: this.data.disabled,
1090
+ placeholder: this.data.placeholder,
1091
+ minValues: this.data.minValues,
1092
+ maxValues: this.data.maxValues,
1093
+ };
1094
+ if (this.data.type == "string") {
1095
+ if (!this.data.options || this.data.options.length < 1)
1096
+ throw new ODSystemError("ODDropdownComponent:build('" + this.id.value + "') => Please provide at least one string option using setOptions().");
1097
+ return new discord.StringSelectMenuBuilder({
1098
+ ...genericOpts,
1099
+ options: this.data.options
1100
+ });
1101
+ }
1102
+ else if (this.data.type == "user") {
1103
+ if (!this.data.users || this.data.users.length < 1)
1104
+ throw new ODSystemError("ODDropdownComponent:build('" + this.id.value + "') => Please provide at least one user option using setUsers().");
1105
+ return new discord.UserSelectMenuBuilder({
1106
+ ...genericOpts,
1107
+ defaultValues: this.data.users.map((u) => ({ id: u.id, type: discord.SelectMenuDefaultValueType.User }))
1108
+ });
1109
+ }
1110
+ else if (this.data.type == "role") {
1111
+ if (!this.data.roles || this.data.roles.length < 1)
1112
+ throw new ODSystemError("ODDropdownComponent:build('" + this.id.value + "') => Please provide at least one role option using setRoles().");
1113
+ return new discord.RoleSelectMenuBuilder({
1114
+ ...genericOpts,
1115
+ defaultValues: this.data.roles.map((r) => ({ id: r.id, type: discord.SelectMenuDefaultValueType.Role }))
1116
+ });
1117
+ }
1118
+ else if (this.data.type == "channel") {
1119
+ if (!this.data.channels || this.data.channels.length < 1)
1120
+ throw new ODSystemError("ODDropdownComponent:build('" + this.id.value + "') => Please provide at least one channel option using setChannels().");
1121
+ return new discord.ChannelSelectMenuBuilder({
1122
+ ...genericOpts,
1123
+ channelTypes: this.data.channelTypes,
1124
+ defaultValues: this.data.channels.map((c) => ({ id: c.id, type: discord.SelectMenuDefaultValueType.Channel }))
1125
+ });
1126
+ }
1127
+ else if (this.data.type == "mentionable") {
1128
+ if (!this.data.mentionables || this.data.mentionables.length < 1)
1129
+ throw new ODSystemError("ODDropdownComponent:build('" + this.id.value + "') => Please provide at least one role/user option using setMentionables().");
1130
+ return new discord.MentionableSelectMenuBuilder({
1131
+ ...genericOpts,
1132
+ defaultValues: this.data.mentionables.map((m) => (m instanceof discord.User ? { id: m.id, type: discord.SelectMenuDefaultValueType.User } : { id: m.id, type: discord.SelectMenuDefaultValueType.Role }))
1133
+ });
1134
+ }
1135
+ else
1136
+ throw new ODSystemError("ODDropdownComponent:build('" + this.id.value + "') => Please set the dropdown type to one of the following: string, user, role, channel, mentionable.");
1137
+ }
1138
+ /**Set the custom id of this dropdown. */
1139
+ setCustomId(id) {
1140
+ this.data.customId = id ?? undefined;
1141
+ return this;
1142
+ }
1143
+ /**Set the type of this dropdown. */
1144
+ setType(type) {
1145
+ this.data.type = type;
1146
+ return this;
1147
+ }
1148
+ /**Set the minimum selection amount of this dropdown. */
1149
+ setMinValues(amount) {
1150
+ this.data.minValues = amount ?? undefined;
1151
+ return this;
1152
+ }
1153
+ /**Set the maximum selection amount of this dropdown. */
1154
+ setMaxValues(amount) {
1155
+ this.data.maxValues = amount ?? undefined;
1156
+ return this;
1157
+ }
1158
+ /**Set the placeholder of this dropdown. */
1159
+ setPlaceholder(placeholder) {
1160
+ this.data.placeholder = placeholder ?? undefined;
1161
+ return this;
1162
+ }
1163
+ /**Disable this dropdown. */
1164
+ setDisabled(disabled) {
1165
+ this.data.disabled = disabled;
1166
+ return this;
1167
+ }
1168
+ /**Set the available channel types of this dropdown. */
1169
+ setChannelTypes(channelTypes) {
1170
+ this.data.channelTypes = channelTypes;
1171
+ return this;
1172
+ }
1173
+ /**Set the options of this dropdown (when `type == "string"`) */
1174
+ setOptions(options) {
1175
+ this.data.options = options;
1176
+ return this;
1177
+ }
1178
+ /**Set the users of this dropdown (when `type == "user"`) */
1179
+ setUsers(users) {
1180
+ this.data.users = users;
1181
+ return this;
1182
+ }
1183
+ /**Set the roles of this dropdown (when `type == "role"`) */
1184
+ setRoles(roles) {
1185
+ this.data.roles = roles;
1186
+ return this;
1187
+ }
1188
+ /**Set the channels of this dropdown (when `type == "channel"`) */
1189
+ setChannels(channels) {
1190
+ this.data.channels = channels;
1191
+ return this;
1192
+ }
1193
+ /**Set the mentionables of this dropdown (when `type == "mentionable"`) */
1194
+ setMentionables(mentionables) {
1195
+ this.data.mentionables = mentionables;
1196
+ return this;
1197
+ }
1198
+ }
1199
+ /**## ODRadioGroupComponent `class`
1200
+ * A radio group component which renders an interactive radio group input inside a modal.
1201
+ */
1202
+ export class ODRadioGroupComponent extends ODComponent {
1203
+ constructor(id, data) {
1204
+ const initData = { required: false, options: [], ...data };
1205
+ super(id, initData);
1206
+ }
1207
+ async build() {
1208
+ if (!this.data.options || this.data.options.length < 2)
1209
+ throw new ODSystemError("ODRadioGroupComponent:build('" + this.id.value + "') => Please provide at least 2 radio options using setOptions().");
1210
+ return new discord.RadioGroupBuilder({
1211
+ custom_id: this.data.customId,
1212
+ required: this.data.required,
1213
+ options: this.data.options
1214
+ });
1215
+ }
1216
+ /**Set the custom id of this radio group. */
1217
+ setCustomId(id) {
1218
+ this.data.customId = id ?? undefined;
1219
+ return this;
1220
+ }
1221
+ /**Mark this radio group as required (At least one option must be selected). */
1222
+ setRequired(required) {
1223
+ this.data.required = required;
1224
+ return this;
1225
+ }
1226
+ /**Set the available radio options (min 2, max 10) */
1227
+ setOptions(options) {
1228
+ this.data.options = options;
1229
+ return this;
1230
+ }
1231
+ }
1232
+ /**## ODCheckboxGroupComponent `class`
1233
+ * A checkbox group component which renders an interactive checkbox group input inside a modal.
1234
+ */
1235
+ export class ODCheckboxGroupComponent extends ODComponent {
1236
+ constructor(id, data) {
1237
+ const initData = { required: false, options: [], ...data };
1238
+ super(id, initData);
1239
+ }
1240
+ async build() {
1241
+ if (!this.data.options || this.data.options.length < 2)
1242
+ throw new ODSystemError("ODCheckboxGroupComponent:build('" + this.id.value + "') => Please provide at least 2 radio options using setOptions().");
1243
+ return new discord.CheckboxGroupBuilder({
1244
+ custom_id: this.data.customId,
1245
+ required: this.data.required,
1246
+ options: this.data.options,
1247
+ min_values: this.data.minValues,
1248
+ max_values: this.data.maxValues
1249
+ });
1250
+ }
1251
+ /**Set the custom id of this checkbox group. */
1252
+ setCustomId(id) {
1253
+ this.data.customId = id ?? undefined;
1254
+ return this;
1255
+ }
1256
+ /**Mark this checkbox group as required (At least one option must be selected). */
1257
+ setRequired(required) {
1258
+ this.data.required = required;
1259
+ return this;
1260
+ }
1261
+ /**Set the available checkbox options (min 2, max 10) */
1262
+ setOptions(options) {
1263
+ this.data.options = options;
1264
+ return this;
1265
+ }
1266
+ /**Set the minimum amount of selected checkboxes. */
1267
+ setMinValues(amount) {
1268
+ this.data.minValues = amount ?? undefined;
1269
+ return this;
1270
+ }
1271
+ /**Set the maximum amount of selected checkboxes. */
1272
+ setMaxValues(amount) {
1273
+ this.data.maxValues = amount ?? undefined;
1274
+ return this;
1275
+ }
1276
+ }
1277
+ /**## ODCheckboxComponent `class`
1278
+ * A checkbox component which renders an interactive checkbox input inside a modal.
1279
+ * The label & description should be set via an `ODLabelComponent`
1280
+ */
1281
+ export class ODCheckboxComponent extends ODComponent {
1282
+ constructor(id, data) {
1283
+ const initData = { default: false, ...data };
1284
+ super(id, initData);
1285
+ }
1286
+ async build() {
1287
+ return new discord.CheckboxBuilder({
1288
+ custom_id: this.data.customId,
1289
+ default: this.data.default
1290
+ });
1291
+ }
1292
+ /**Set the custom id of this checkbox. */
1293
+ setCustomId(id) {
1294
+ this.data.customId = id ?? undefined;
1295
+ return this;
1296
+ }
1297
+ /**Mark this checkbox as enabled by default. */
1298
+ setDefault(enabledByDefault) {
1299
+ this.data.default = enabledByDefault;
1300
+ return this;
1301
+ }
1302
+ }
1303
+ /**## ODFileUploadComponent `class`
1304
+ * A file upload component which allows users to upload one or multiple files inside a modal.
1305
+ * The label & description should be set via an `ODLabelComponent`
1306
+ */
1307
+ export class ODFileUploadComponent extends ODComponent {
1308
+ constructor(id, data) {
1309
+ const initData = { required: false, ...data };
1310
+ super(id, initData);
1311
+ }
1312
+ async build() {
1313
+ if (typeof this.data.minAmount == "number" && !(this.data.minAmount >= 0 && this.data.minAmount <= 10))
1314
+ throw new ODSystemError("ODFileUploadComponent:build('" + this.id.value + "') => Minimum upload amount must be a value from 0 to 10.");
1315
+ if (typeof this.data.maxAmount == "number" && !(this.data.maxAmount >= 1 && this.data.maxAmount <= 10))
1316
+ throw new ODSystemError("ODFileUploadComponent:build('" + this.id.value + "') => Maximum upload amount must be a value from 1 to 10.");
1317
+ return new discord.FileUploadBuilder({
1318
+ custom_id: this.data.customId,
1319
+ required: this.data.required,
1320
+ min_values: this.data.minAmount,
1321
+ max_values: this.data.maxAmount
1322
+ });
1323
+ }
1324
+ /**Set the custom id of this dropdown. */
1325
+ setCustomId(id) {
1326
+ this.data.customId = id ?? undefined;
1327
+ return this;
1328
+ }
1329
+ /**Mark this file upload as required. */
1330
+ setRequired(required) {
1331
+ this.data.required = required;
1332
+ return this;
1333
+ }
1334
+ /**Set the minimum amount of files to upload (0-10). */
1335
+ setMinAmount(amount) {
1336
+ this.data.minAmount = amount ?? undefined;
1337
+ return this;
1338
+ }
1339
+ /**Set the maximum amount of files to upload (1-10). */
1340
+ setMaxAmount(amount) {
1341
+ this.data.maxAmount = amount ?? undefined;
1342
+ return this;
1343
+ }
1344
+ }