@open-discord-bots/framework 0.3.14 → 0.3.15

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 (41) hide show
  1. package/dist/api/main.js +1 -1
  2. package/dist/api/modules/responder.js +50 -26
  3. package/package.json +1 -1
  4. package/src/api/index.ts +0 -31
  5. package/src/api/main.ts +0 -203
  6. package/src/api/modules/action.ts +0 -89
  7. package/src/api/modules/base.ts +0 -845
  8. package/src/api/modules/builder.ts +0 -1755
  9. package/src/api/modules/checker.ts +0 -1826
  10. package/src/api/modules/client.ts +0 -2345
  11. package/src/api/modules/code.ts +0 -84
  12. package/src/api/modules/component.ts +0 -2000
  13. package/src/api/modules/config.ts +0 -264
  14. package/src/api/modules/console.ts +0 -697
  15. package/src/api/modules/cooldown.ts +0 -369
  16. package/src/api/modules/database.ts +0 -321
  17. package/src/api/modules/event.ts +0 -123
  18. package/src/api/modules/flag.ts +0 -99
  19. package/src/api/modules/fuse.ts +0 -365
  20. package/src/api/modules/helpmenu.ts +0 -273
  21. package/src/api/modules/language.ts +0 -230
  22. package/src/api/modules/permission.ts +0 -363
  23. package/src/api/modules/plugin.ts +0 -294
  24. package/src/api/modules/post.ts +0 -137
  25. package/src/api/modules/progressbar.ts +0 -370
  26. package/src/api/modules/responder.ts +0 -1625
  27. package/src/api/modules/session.ts +0 -181
  28. package/src/api/modules/startscreen.ts +0 -345
  29. package/src/api/modules/state.ts +0 -298
  30. package/src/api/modules/statistic.ts +0 -380
  31. package/src/api/modules/verifybar.ts +0 -68
  32. package/src/api/modules/worker.ts +0 -119
  33. package/src/cli/editConfig.ts +0 -930
  34. package/src/cli/index.ts +0 -152
  35. package/src/index.ts +0 -8
  36. package/src/startup/compilation.ts +0 -204
  37. package/src/startup/dump.ts +0 -46
  38. package/src/startup/errorHandling.ts +0 -42
  39. package/src/startup/pluginLauncher.ts +0 -265
  40. package/src/utilities/index.ts +0 -229
  41. package/tools/cleanup.js +0 -2
@@ -1,2000 +0,0 @@
1
- ///////////////////////////////////////
2
- //COMPONENTS MODULE
3
- ///////////////////////////////////////
4
- import { ODId, ODValidId, ODSystemError, ODManagerData, ODNoGeneric, ODManager, ODValidButtonColor, ODInterfaceWithPartialProperty } from "./base.js"
5
- import * as discord from "discord.js"
6
- import { ODWorkerManager, ODWorkerCallback, ODWorker } from "./worker.js"
7
- import { ODDebugger } from "./console.js"
8
- import { ODMessage, ODMessageInstance } from "./builder.js"
9
-
10
- /**## ODComponentFactoryInstance `class`
11
- * An Open Discord component factory instance.
12
- *
13
- * It will contain the final root component which is returned by an `ODComponentFactory`.
14
- * This component can be used in another `ODComponentFactory` or rendered to a message/modal.
15
- */
16
- export class ODComponentFactoryInstance<Component extends ODComponent<object,any>> {
17
- /**The root component of this factory. */
18
- private rootComponent: Component|null = null
19
-
20
- /**The root component of this factory. */
21
- getComponent(){
22
- return this.rootComponent
23
- }
24
- /**Set the root component of this factory. */
25
- setComponent(c:Component|null){
26
- this.rootComponent = c
27
- }
28
- }
29
-
30
- /**## ODComponentFactory `class`
31
- * An Open Discord component factory.
32
- *
33
- * It is a collection of functions/workers/hooks which will build a Discord message/modal component from scratch.
34
- * Plugins can intercept and modify these workers to replace default behaviour or layout.
35
- */
36
- export class ODComponentFactory<Component extends ODComponent<object,any>,Origin extends string,Params,WorkerIds extends string = string> extends ODManagerData {
37
- /**A collection of all workers for this component factory. */
38
- workers: ODWorkerManager<ODComponentFactoryInstance<Component>,Origin,Params,WorkerIds>
39
-
40
- constructor(id:ODValidId, callback?:ODWorkerCallback<ODComponentFactoryInstance<Component>,Origin,Params>, priority?:number, callbackId?:ODValidId){
41
- super(id)
42
- this.workers = new ODWorkerManager("ascending")
43
- if (callback) this.workers.add(new ODWorker(callbackId ? callbackId : id,priority ?? 0,callback))
44
- }
45
- /**Run all workers and return the resulting component. */
46
- async build(origin:Origin, params:Params): Promise<ODComponentInferBuildResult<Component>> {
47
- const instance = new ODComponentFactoryInstance<Component>()
48
- await this.workers.executeWorkers(instance,origin,params)
49
- const rootComponent = instance.getComponent()
50
- if (!rootComponent) throw new ODSystemError("ODComponentFactory.build() --> Failed to build component! (id: "+this.id.value+")")
51
- return rootComponent.build()
52
- }
53
- /**Duplicate this component factory. Warning: If workers access external variables (outside parameters), the clone will still use those variables. This might result in unexpected behaviour! */
54
- duplicate(newId?:ODValidId): ODComponentFactory<Component,Origin,Params,WorkerIds> {
55
- const newMessage = new ODComponentFactory<Component,Origin,Params,WorkerIds>(newId ?? this.id.value)
56
- for (const worker of this.workers.getAll()){
57
- newMessage.workers.add(worker.duplicate())
58
- }
59
- return newMessage
60
- }
61
- }
62
-
63
- /**## ODComponentManagerIdConstraint `type`
64
- * The constraint/layout for id mappings/interfaces of the `ODComponentManager` class.
65
- */
66
- export type ODComponentManagerIdConstraint = Record<string,{origin:string,params:object,workers:string}>
67
-
68
- /**## ODBaseComponentManager `class`
69
- * A generic Open Discord component manager.
70
- *
71
- * It contains a collection of all Open Discord component factories. You can:
72
- * - Add your own message/modal component factories
73
- * - Modify existing message/modal component factories
74
- *
75
- * Messages created using this system are not compatible with `ODBuilder` messages!
76
- */
77
- export class ODBaseComponentManager<IdList extends ODComponentManagerIdConstraint = ODComponentManagerIdConstraint,Component extends ODComponent<object,any> = ODComponent<object,any>> extends ODManager<ODComponentFactory<Component,string,{},string>> {
78
- get<FactoryId extends keyof ODNoGeneric<IdList>>(id:FactoryId): ODComponentFactory<Component,IdList[FactoryId]["origin"],IdList[FactoryId]["params"],IdList[FactoryId]["workers"]>
79
- get(id:ODValidId): ODComponentFactory<Component,string,{},string>|null
80
-
81
- get(id:ODValidId): ODComponentFactory<Component,string,{},string>|null {
82
- return super.get(id)
83
- }
84
-
85
- remove<FactoryId extends keyof ODNoGeneric<IdList>>(id:FactoryId): ODComponentFactory<Component,IdList[FactoryId]["origin"],IdList[FactoryId]["params"],IdList[FactoryId]["workers"]>
86
- remove(id:ODValidId): ODComponentFactory<Component,string,{},string>|null
87
-
88
- remove(id:ODValidId): ODComponentFactory<Component,string,{},string>|null {
89
- return super.remove(id)
90
- }
91
-
92
- exists(id:keyof ODNoGeneric<IdList>): boolean
93
- exists(id:ODValidId): boolean
94
-
95
- exists(id:ODValidId): boolean {
96
- return super.exists(id)
97
- }
98
- }
99
-
100
-
101
- /**## ODComponentModifierManagerIdConstraint `type`
102
- * The constraint/layout for id mappings/interfaces of the `ODComponentModifierManager` class.
103
- */
104
- export type ODComponentModifierManagerIdConstraint = Record<string,ODMessageComponentModifier<string,{},string>>
105
-
106
- /**## ODComponentModifierManager `class`
107
- * An Open Discord component modifier manager.
108
- *
109
- * It contains a collection of all `ODMessageComponentModifier`'s. You can:
110
- * - Patch, modify, expand or update existing messages
111
- * - It Does not affect the original message (cloned)
112
- */
113
- export class ODComponentModifierManager<IdList extends ODComponentModifierManagerIdConstraint = ODComponentModifierManagerIdConstraint> extends ODManager<ODMessageComponentModifier<string,{},string>> {
114
- constructor(debug:ODDebugger){
115
- super(debug,"component modifier")
116
- }
117
-
118
- get<ModifierId extends keyof ODNoGeneric<IdList>>(id:ModifierId): IdList[ModifierId]
119
- get(id:ODValidId): ODMessageComponentModifier<string,{},string>|null
120
-
121
- get(id:ODValidId): ODMessageComponentModifier<string,{},string>|null {
122
- return super.get(id)
123
- }
124
-
125
- remove<ModifierId extends keyof ODNoGeneric<IdList>>(id:ModifierId): IdList[ModifierId]
126
- remove(id:ODValidId): ODMessageComponentModifier<string,{},string>|null
127
-
128
- remove(id:ODValidId): ODMessageComponentModifier<string,{},string>|null {
129
- return super.remove(id)
130
- }
131
-
132
- exists(id:keyof ODNoGeneric<IdList>): boolean
133
- exists(id:ODValidId): boolean
134
-
135
- exists(id:ODValidId): boolean {
136
- return super.exists(id)
137
- }
138
- }
139
-
140
- /**## ODSharedComponentManager `class
141
- * A special class with types for shared message/modal `ODComponent`'s.
142
- * Create button, dropdown or any other layout component template to use them in messages & modals.
143
- */
144
- export class ODSharedComponentManager<IdList extends ODComponentManagerIdConstraint = ODComponentManagerIdConstraint> extends ODBaseComponentManager<IdList,ODComponent<object,any>> {
145
- constructor(debug:ODDebugger){
146
- super(debug,"shared component")
147
- }
148
- }
149
-
150
- /**## ODMessageComponentManager `class
151
- * A special class with types for `ODMessageComponent`'s.
152
- * Create message templates to use as replies and make use of shared components.
153
- */
154
- export class ODMessageComponentManager<IdList extends ODComponentManagerIdConstraint = ODComponentManagerIdConstraint> extends ODBaseComponentManager<IdList,ODMessageComponent|ODSimpleMessageComponent> {
155
- constructor(debug:ODDebugger){
156
- super(debug,"message component")
157
- }
158
- }
159
-
160
- /**## ODModalComponentManager `class
161
- * A special class with types for `ODModalComponent`'s.
162
- * Create modal templates to use as forms and make use of shared components.
163
- */
164
- export class ODModalComponentManager<IdList extends ODComponentManagerIdConstraint = ODComponentManagerIdConstraint> extends ODBaseComponentManager<IdList,ODModalComponent> {
165
- constructor(debug:ODDebugger){
166
- super(debug,"modal component")
167
- }
168
- }
169
-
170
- /**## ODComponentManager `class`
171
- * An Open Discord component manager.
172
- *
173
- * Create message & modal templates, re-use components and design all visual elements of the bot.
174
- *
175
- * Using the Open Discord component system has many advantages compared to vanilla `discord.js`:
176
- * - Plugins can extend, edit & replace messages & components
177
- * - Includes automatic error handling
178
- * - Independent workers/hooks (with priority)
179
- * - Fail-safe design using try-catch
180
- * - Automatic switch between components v2 and legacy components depending on message requirements
181
- * - Get to know the origin of the request (e.g. button, dropdown, modal, ...)
182
- * - And so much more!
183
- */
184
- export class ODComponentManager<
185
- SharedIdList extends ODComponentManagerIdConstraint = ODComponentManagerIdConstraint,
186
- MessageIdList extends ODComponentManagerIdConstraint = ODComponentManagerIdConstraint,
187
- ModalIdList extends ODComponentManagerIdConstraint = ODComponentManagerIdConstraint,
188
- ModifierIdList extends ODComponentModifierManagerIdConstraint = ODComponentModifierManagerIdConstraint
189
- > {
190
- /**The manager for all shared components. */
191
- shared: ODSharedComponentManager<SharedIdList>
192
- /**The manager for all messages components. */
193
- messages: ODMessageComponentManager<MessageIdList>
194
- /**The manager for all modals components. */
195
- modals: ODModalComponentManager<ModalIdList>
196
- /**The collection of all component modifiers. */
197
- modifiers: ODComponentModifierManager<ModifierIdList>
198
-
199
- constructor(debug:ODDebugger){
200
- this.shared = new ODSharedComponentManager(debug)
201
- this.messages = new ODMessageComponentManager(debug)
202
- this.modals = new ODModalComponentManager(debug)
203
- this.modifiers = new ODComponentModifierManager(debug)
204
- }
205
- }
206
-
207
- ///////////////////////////////////////
208
- // GENERIC COMPONENT DEFINITIONS //
209
- ///////////////////////////////////////
210
-
211
- /**## ODComponentInferBuildResult `type`
212
- * Infer the build result of a certain component.
213
- */
214
- export type ODComponentInferBuildResult<Component> = Component extends ODComponent<object,infer BuildResult> ? BuildResult : never
215
-
216
- /**## ODComponentType `type`
217
- * The type of an `ODComponent`.
218
- */
219
- export type ODComponentType = "message"|"simple-message"|"modal"|"action-row"|"container"|"section"|"label"|"separator"|"text"|"file"|"gallery"|"thumbnail"|"simple-content"|"simple-embed"|"simple-poll"|"button"|"short-input"|"paragraph-input"|"dropdown"|"radio-group"|"checkbox-group"|"checkbox"|"file-upload"
220
-
221
- /**## ODComponentType `type`
222
- * Get the `ODComponent` class for a specific `ODComponentType`.
223
- */
224
- export interface ODComponentForType {
225
- "message":ODMessageComponent,
226
- "simple-message":ODSimpleMessageComponent,
227
- "modal":ODModalComponent,
228
- "action-row":ODActionRowComponent,
229
- "container":ODContainerComponent,
230
- "section":ODSectionComponent,
231
- "label":ODLabelComponent,
232
- "separator":ODSeparatorComponent,
233
- "text":ODTextComponent,
234
- "file":ODFileComponent,
235
- "gallery":ODGalleryComponent,
236
- "thumbnail":ODThumbnailComponent,
237
- "simple-content":ODContentComponent,
238
- "simple-embed":ODEmbedComponent,
239
- "simple-poll":ODPollComponent,
240
- "button":ODButtonComponent,
241
- "short-input":ODShortInputComponent,
242
- "paragraph-input":ODParagraphInputComponent,
243
- "dropdown":ODDropdownComponent,
244
- "radio-group":ODRadioGroupComponent,
245
- "checkbox-group":ODCheckboxGroupComponent,
246
- "checkbox":ODCheckboxComponent,
247
- "file-upload":ODFileUploadComponent,
248
- }
249
-
250
- /**## ODComponent `class`
251
- * An Open Discord message/modal component.
252
- *
253
- * This class itself doesn't do anything, but is a blueprint for other
254
- * `ODComponent` classes which represent the new Discord message/modal components.
255
- */
256
- export abstract class ODComponent<Data extends object,BuildResult,Type extends ODComponentType = ODComponentType> {
257
- /**The id of this message/modal component. */
258
- id: ODId
259
- /**The data or configuration of this message/modal component. */
260
- readonly data: Data
261
- /**The type of this component. */
262
- readonly type: Type
263
-
264
- constructor(id:ODValidId,type:Type,data:Data){
265
- this.id = new ODId(id)
266
- this.data = data
267
- this.type = type
268
- }
269
-
270
- /**Build this component. Returns `null` when invalid. */
271
- abstract build(): Promise<BuildResult|null>|BuildResult|null
272
- }
273
-
274
- /**## ODGroupComponent `class`
275
- * An Open Discord message/modal component with children.
276
- *
277
- * This class itself doesn't do anything, but is a blueprint for other
278
- * `ODGroupComponent` classes which represent the new Discord message/modal components.
279
- */
280
- export abstract class ODGroupComponent<Data extends object,ChildComponent extends ODComponent<object,any>,BuildResult> extends ODComponent<Data,BuildResult> {
281
- /**The collection of child components. */
282
- children: ChildComponent[] = []
283
-
284
- /**Add a new component to this group. There are multiple modes available:
285
- * - `start`: insert at the start of the list.
286
- * - `end`: insert at the end of the list.
287
- * - `before`: insert before an existing component `referenceId` (`start` if `referenceId` is invalid)
288
- * - `after`: insert after an existing component `referenceId` (`end` if `referenceId` is invalid)
289
- * - `index`: insert at a certain index `referenceIndex` (`end` if `referenceIndex` is invalid)
290
- */
291
- addComponent(c:ChildComponent,mode:"start"|"end"): void
292
- addComponent(c:ChildComponent,mode:"before"|"after",referenceId:ODValidId): void
293
- addComponent(c:ChildComponent,mode:"index",referenceIndex:number): void
294
- addComponent(c:ChildComponent,mode:"start"|"end"|"before"|"after"|"index" = "start",reference?:ODValidId|number){
295
- if (mode == "start") this.children.unshift(c)
296
- else if (mode == "end") this.children.push(c)
297
- else if (mode == "before"){
298
- if (!reference || !this.children.find((c) => c.id.value === new ODId(reference).value)) this.children.unshift(c)
299
- else{
300
- const referenceIndex = this.children.findIndex((c) => c.id.value === new ODId(reference).value)
301
- this.children.splice(referenceIndex,0,c) //insert at position 'referenceIndex' (before)
302
- }
303
- }else if (mode == "after"){
304
- if (!reference || !this.children.find((c) => c.id.value === new ODId(reference).value)) this.children.push(c)
305
- else{
306
- const referenceIndex = this.children.findIndex((c) => c.id.value === new ODId(reference).value)
307
- this.children.splice(referenceIndex+1,0,c) //insert at position 'referenceIndex+1' (after)
308
- }
309
- }else if (mode == "index"){
310
- if (!reference || typeof reference !== "number") this.children.push(c)
311
- else{
312
- this.children.splice(reference,0,c) //insert at position 'reference'
313
- }
314
- }
315
- }
316
- /**Get a component with a certain ID in this group. Returns `null` if non-existent. Also able to search for components recursively. */
317
- getComponent(id:ODValidId): ChildComponent|null
318
- getComponent(id:ODValidId,recursive:true,recursiveLimit?:number): ODComponent<any,any,ODComponentType>|null
319
- getComponent(id:ODValidId,recursive?:boolean,recursiveLimit:number=15){
320
- const component = this.children.find((c) => c.id.value === new ODId(id).value)
321
- if (component) return component
322
- else if (recursive && (recursiveLimit > 0)){
323
- for (const child of this.children){
324
- if (child instanceof ODGroupComponent){
325
- const finalComponent = child.getComponent(id,recursive,recursiveLimit-1) as ODComponent<any,any,ODComponentType>
326
- if (finalComponent) return finalComponent
327
- }else if (child instanceof ODParentComponent){
328
- const finalComponent = child.child as ODComponent<any,any,ODComponentType>
329
- if (finalComponent.id.value === new ODId(id).value) return finalComponent
330
- }
331
- }
332
- return null
333
- }else return null
334
- }
335
- /**Get all components of a certain type in this group. Also able to search for components recursively. */
336
- getComponentsOfType<Type extends ODComponentType>(type:Type): ODComponentForType[Type][]
337
- getComponentsOfType<Type extends ODComponentType>(type:Type,recursive:true,recursiveLimit?:number): ODComponentForType[Type][]
338
- getComponentsOfType(type:ODComponentType,recursive?:boolean,recursiveLimit:number=15){
339
- if (recursive && (recursiveLimit > 0)){
340
- const finalComponents: ODComponent<any,any,ODComponentType>[] = [...this.children.filter((c) => c.type === type)]
341
-
342
- for (const child of this.children){
343
- if (child instanceof ODGroupComponent){
344
- finalComponents.push(...(child.getComponentsOfType(type,recursive,recursiveLimit-1) as ODComponent<any,any,ODComponentType>[]))
345
-
346
- }else if (child instanceof ODParentComponent){
347
- const finalComponent = child.child as ODComponent<any,any,ODComponentType>
348
- if (finalComponent.type === type) finalComponents.push(finalComponent)
349
- }
350
- }
351
- return finalComponents
352
- }else{
353
- const finalComponents: ChildComponent[] = [...this.children.filter((c) => c.type === type)]
354
- return finalComponents
355
- }
356
- }
357
- /**Get the position of a component with a certain ID in this group. Returns `-1` if non-existent. */
358
- getComponentPosition(id:ODValidId){
359
- return this.children.findIndex((c) => c.id.value === new ODId(id).value)
360
- }
361
- /**List all child components of this group. */
362
- listComponent(){
363
- return this.children
364
- }
365
- /**Returns if a component with a certain ID exists in this group. */
366
- existsComponent(id:ODValidId){
367
- const component = this.children.find((c) => c.id.value === new ODId(id).value)
368
- return component ? true : false
369
- }
370
- /**Remove a component with a certain ID from this group. Returns the removed component or `null if non-existent. */
371
- removeComponent(id:ODValidId){
372
- const index = this.children.findIndex((c) => c.id.value === new ODId(id).value)
373
- if (index < 0) return null
374
- else return this.children.splice(index,1)[0]
375
- }
376
- /**Remove all child components from this group. Returns the removed components. */
377
- clearComponents(){
378
- const removedChildren = this.children
379
- this.children = []
380
- return removedChildren
381
- }
382
- /**Moves an existing component to a new location in this group. There are multiple modes available:
383
- * - `start`: move to the start of the list.
384
- * - `end`: move to the end of the list.
385
- * - `before`: move before an existing component `referenceId` (`start` if `referenceId` is invalid)
386
- * - `after`: move after an existing component `referenceId` (`end` if `referenceId` is invalid)
387
- * - `index`: move to a certain index `referenceIndex` (`end` if `referenceIndex` is invalid)
388
- */
389
- moveComponent(id:ODValidId,mode:"start"|"end"): void
390
- moveComponent(id:ODValidId,mode:"before"|"after",referenceId:ODValidId): void
391
- moveComponent(id:ODValidId,mode:"index",referenceIndex:number): void
392
- moveComponent(id:ODValidId,mode:"start"|"end"|"before"|"after"|"index" = "start",reference?:ODValidId|number){
393
- const component = this.removeComponent(id)
394
- if (component){
395
- if (mode == "start" || mode == "end") this.addComponent(component,mode)
396
- if ((mode == "before" || mode == "after") && reference) this.addComponent(component,mode,reference)
397
- if (mode == "index" && typeof reference == "number") this.addComponent(component,mode,reference)
398
- return
399
- }
400
- }
401
- }
402
-
403
- /**## ODParentComponent `class`
404
- * An Open Discord message/modal component with a single child.
405
- *
406
- * This class itself doesn't do anything, but is a blueprint for other
407
- * `ODParentComponent` classes which represent the new Discord message/modal components.
408
- */
409
- export abstract class ODParentComponent<Data extends object,ChildComponent extends ODComponent<object,any>,BuildResult> extends ODComponent<Data,BuildResult> {
410
- /**The child component of this parent. */
411
- private rawChild: ChildComponent|null = null
412
-
413
- /**The child component of this parent. */
414
- get child(){
415
- return this.rawChild
416
- }
417
- /**Set the child component of this parent. */
418
- setComponent(c:ChildComponent|null){
419
- this.rawChild = c
420
- }
421
- }
422
-
423
- /////////////////////////////
424
- // COMPONENT MODIFIERS //
425
- /////////////////////////////
426
-
427
- /**## ODMessageComponentModifier `class`
428
- * This is an Open Discord message component modifier.
429
- *
430
- * It contains a worker which is can be added to a message.
431
- *
432
- * The original message is preserved and a duplicate of `ODMessage` or `ODComponentFactory` is returned.
433
- *
434
- * Warning: If workers access external variables (outside parameters), the clone will still use those variables. This might result in unexpected behaviour!
435
- */
436
- export class ODMessageComponentModifier<Origin extends string,Params,WorkerIds extends string> extends ODManagerData {
437
- /**The workers which will modify the message. */
438
- workers: ODWorkerManager<ODMessageInstance|ODComponentFactoryInstance<ODMessageComponent>,Origin,Params,WorkerIds>
439
-
440
- constructor(id:ODValidId,callback?:ODWorkerCallback<ODMessageInstance|ODComponentFactoryInstance<ODMessageComponent>,Origin,Params>, priority?:number, callbackId?:ODValidId){
441
- super(id)
442
- this.workers = new ODWorkerManager("ascending")
443
- if (callback) this.workers.add(new ODWorker(callbackId ? callbackId : id,priority ?? 0,callback))
444
- }
445
-
446
- /**Modify an `ODMessage` or `ODComponentFactory` with these workers. A copy will be returned and the original is preserved. */
447
- modify<Message extends ODMessage<any,any,any>|ODComponentFactory<ODMessageComponent,any,any,any>>(message:Message,origin:Origin,params:Params): Message {
448
- const newMsg = message.duplicate(message.id.value+"-VERIFYBAR") as Message
449
- newMsg.workers.add(new ODWorker<any,any,any>("opendiscord:VERIFYBAR",1000,async (msgInstance,msgParams,msgOrigin,msgCancel) => {
450
- await this.workers.executeWorkers(msgInstance,origin,params)
451
- }))
452
- return newMsg
453
- }
454
- }
455
-
456
- //////////////////////////////////////
457
- // GLOBAL COMPONENT DEFINITIONS //
458
- //////////////////////////////////////
459
-
460
- /**## ODMessageComponentData `type`
461
- * The configurable settings/options for the `ODMessageComponent`.
462
- */
463
- export interface ODMessageComponentData {
464
- /**Should the message be sent as ephemeral? */
465
- ephemeral?:boolean,
466
- /**Suppress/hide embeds. */
467
- supressEmbeds?:boolean,
468
- /**Do not send notifications to mentioned users or roles. */
469
- supressNotifications?:boolean
470
- /**Additional options that aren't covered by the Open Discord api!*/
471
- additionalOptions?:Omit<discord.MessageCreateOptions,"poll"|"content"|"embeds"|"components"|"files"|"flags"|"stickers">,
472
- /**Add additional files which can be used in components as `attachment://...` */
473
- additionalAttachments?:discord.AttachmentBuilder[]
474
- }
475
-
476
- /**## ODValidMessageComponents `type`
477
- * A collection of all valid top-level components that can be sent in a message.
478
- */
479
- export type ODValidMessageComponents = ODTextComponent|ODFileComponent|ODGalleryComponent|ODActionRowComponent|ODContainerComponent|ODSectionComponent|ODSeparatorComponent
480
-
481
- /**## ODMessageComponentBuildResult `type`
482
- * The constructed message from an `ODMessageComponent`.
483
- */
484
- export interface ODMessageComponentBuildResult {
485
- /**The message to send. */
486
- msg:discord.MessageCreateOptions,
487
- /**Is this message using Components V2? */
488
- componentsV2:boolean,
489
- /**Should the message be sent as ephemeral? */
490
- ephemeral:boolean,
491
- /**Suppress/hide embeds. */
492
- supressEmbeds:boolean,
493
- /**Do not send notifications to mentioned users or roles. */
494
- supressNotifications:boolean,
495
- /**The id of the `ODMessageComponent` this message was built with. */
496
- id:ODId
497
- }
498
-
499
- /**## ODMessageComponent `class`
500
- * A message builder with **components v2** support.
501
- * Add items to this message using `addComponent()`.
502
- *
503
- * Use `ODSimpleMessageComponent` for components v1, polls, embeds, etc
504
- */
505
- export class ODMessageComponent extends ODGroupComponent<ODMessageComponentData,ODValidMessageComponents,ODMessageComponentBuildResult> {
506
- constructor(id:ODValidId,data?:Partial<ODMessageComponentData>){
507
- const initData: ODMessageComponentData = {...data}
508
- super(id,"message",initData)
509
- }
510
-
511
- async build(){
512
- if (this.children.length < 1) throw new ODSystemError("ODMessageComponent:build('"+this.id.value+"') => Requires at least one child component.")
513
-
514
- const attachments: discord.AttachmentBuilder[] = [...(this.data.additionalAttachments ?? [])]
515
- const components: discord.JSONEncodable<discord.APIMessageTopLevelComponent>[] = []
516
-
517
- for (const component of this.children){
518
- if (component instanceof ODFileComponent){
519
- //ODFileComponent (special)
520
- const res = await component.build()
521
- if (res) components.push(res.file)
522
- if (res?.attachment) attachments.push(res.attachment)
523
-
524
- }else if (component instanceof ODGalleryComponent){
525
- //ODGalleryComponent (special)
526
- const res = await component.build()
527
- if (res) components.push(res.gallery)
528
- if (res?.attachments) attachments.push(...res.attachments)
529
- }else if (component instanceof ODContainerComponent){
530
- //ODContainerComponent (special)
531
- const res = await component.build()
532
- if (res) components.push(res.container)
533
- if (res?.attachments) attachments.push(...res.attachments)
534
- }else{
535
- //general ODComponent's
536
- const res = await component.build()
537
- if (res) components.push(res)
538
- }
539
- }
540
-
541
- return {
542
- id:new ODId(this.id),
543
- msg:{
544
- components,
545
- files:attachments,
546
- ...this.data.additionalOptions
547
- },
548
- componentsV2:true,
549
- ephemeral:this.data.ephemeral ?? false,
550
- supressEmbeds:this.data.supressEmbeds ?? false,
551
- supressNotifications:this.data.supressNotifications ?? false
552
- }
553
-
554
- }
555
-
556
- /**Enable/disable ephemeral mode. */
557
- setEphemeral(value:boolean){
558
- this.data.ephemeral = value
559
- }
560
- /**Enable supress (hide) embeds mode. */
561
- setSupressEmbeds(value:boolean){
562
- this.data.supressEmbeds = value
563
- }
564
- /**Enable supress (hide) notifications mode. */
565
- setSupressNotifications(value:boolean){
566
- this.data.supressNotifications = value
567
- }
568
- /**Add an additional attachment which can be used in components as `attachment://...` */
569
- addAdditionalAttachments(...attachments:discord.AttachmentBuilder[]){
570
- if (!this.data.additionalAttachments) this.data.additionalAttachments = []
571
- this.data.additionalAttachments.push(...attachments)
572
- }
573
- }
574
-
575
-
576
- /**## ODSimpleMessageComponentData `type`
577
- * The configurable settings/options for the `ODSimpleMessageComponent`.
578
- */
579
- export interface ODSimpleMessageComponentData {
580
- /**Should the message be sent as ephemeral? */
581
- ephemeral?:boolean,
582
- /**Suppress/hide embeds. */
583
- supressEmbeds?:boolean,
584
- /**Do not send notifications to mentioned users or roles. */
585
- supressNotifications?:boolean
586
- /**Additional options that aren't covered by the Open Discord api!*/
587
- additionalOptions?:Omit<discord.MessageCreateOptions,"poll"|"content"|"embeds"|"components"|"files"|"flags">,
588
- /**Add additional files which can be used in components as `attachment://...` */
589
- additionalAttachments?:discord.AttachmentBuilder[]
590
- }
591
-
592
- /**## ODValidSimpleMessageComponents `type`
593
- * A collection of all valid top-level components that can be sent in a simple message (components v1).
594
- */
595
- export type ODValidSimpleMessageComponents = ODContentComponent|ODEmbedComponent|ODFileComponent|ODPollComponent
596
-
597
- /**## ODSimpleMessageComponent `class`
598
- * A message builder with **components v1** support.
599
- * Add items to this message using `addComponent()`.
600
- *
601
- * Use `ODMessageComponent` for components v2, components, containers, etc
602
- */
603
- export class ODSimpleMessageComponent extends ODGroupComponent<ODSimpleMessageComponentData,ODValidSimpleMessageComponents,ODMessageComponentBuildResult> {
604
- constructor(id:ODValidId,data?:Partial<ODMessageComponentData>){
605
- const initData: ODMessageComponentData = {...data}
606
- super(id,"simple-message",initData)
607
- }
608
-
609
- async build(){
610
- if (this.children.length < 1) throw new ODSystemError("ODMessageComponent:build('"+this.id.value+"') => Requires at least one child component.")
611
-
612
- const attachments: discord.AttachmentBuilder[] = [...(this.data.additionalAttachments ?? [])]
613
- const embeds: discord.EmbedBuilder[] = []
614
- let content: string|undefined = undefined
615
- let poll: discord.PollData|undefined = undefined
616
-
617
- for (const component of this.children){
618
- if (component instanceof ODFileComponent){
619
- //ODFileComponent (special)
620
- const res = await component.build()
621
- if (res?.attachment) attachments.push(res.attachment)
622
-
623
- }else if (component instanceof ODContentComponent){
624
- //ODContentComponent (special)
625
- const res = await component.build()
626
- if (res) content = res.content
627
-
628
- }else if (component instanceof ODEmbedComponent){
629
- //ODEmbedComponent (special)
630
- const res = await component.build()
631
- if (res) embeds.push(res)
632
-
633
- }else{
634
- //ODPollComponent (special)
635
- const res = await component.build()
636
- if (res) poll = res
637
- }
638
- }
639
-
640
- return {
641
- id:new ODId(this.id),
642
- msg:{
643
- content,
644
- embeds,
645
- poll,
646
- files:attachments,
647
- ...this.data.additionalOptions
648
- },
649
- componentsV2:false,
650
- ephemeral:this.data.ephemeral ?? false,
651
- supressEmbeds:this.data.supressEmbeds ?? false,
652
- supressNotifications:this.data.supressNotifications ?? false
653
- }
654
- }
655
-
656
- /**Enable/disable ephemeral mode. */
657
- setEphemeral(value:boolean){
658
- this.data.ephemeral = value
659
- }
660
- /**Enable supress (hide) embeds mode. */
661
- setSupressEmbeds(value:boolean){
662
- this.data.supressEmbeds = value
663
- }
664
- /**Enable supress (hide) notifications mode. */
665
- setSupressNotifications(value:boolean){
666
- this.data.supressNotifications = value
667
- }
668
- /**Add an additional attachment which can be used in components as `attachment://...` */
669
- addAdditionalAttachments(...attachments:discord.AttachmentBuilder[]){
670
- if (!this.data.additionalAttachments) this.data.additionalAttachments = []
671
- this.data.additionalAttachments.push(...attachments)
672
- }
673
- }
674
-
675
-
676
- /**## ODModalComponentData `type`
677
- * The configurable settings/options for the `ODModalComponent`.
678
- */
679
- export interface ODModalComponentData {
680
- /**The title of the modal (max 45 characters). */
681
- title:string,
682
- /**The custom id of this modal. */
683
- customId?:string
684
- }
685
-
686
- /**## ODValidModalComponents `type`
687
- * A collection of all valid top-level components that can be sent in a message.
688
- */
689
- export type ODValidModalComponents = ODLabelComponent|ODTextComponent
690
-
691
- /**## ODModalComponent `class`
692
- * A modal builder with **components v2** support.
693
- * Add questions, select menu's & labels to this modal using `addComponent()`.
694
- */
695
- export class ODModalComponent extends ODGroupComponent<ODModalComponentData,ODValidModalComponents,discord.ModalBuilder> {
696
- constructor(id:ODValidId,data?:Partial<ODModalComponentData>){
697
- const initData: ODModalComponentData = {title:"<empty>",...data}
698
- super(id,"modal",initData)
699
- }
700
-
701
- async build(){
702
- if (this.children.length < 1) throw new ODSystemError("ODModalComponent:build('"+this.id.value+"') => Requires at least one child component.")
703
- if (this.children.length > 5) throw new ODSystemError("ODModalComponent:build('"+this.id.value+"') => A modal doesn't support more than 5 components.")
704
-
705
- const components: (discord.APITextDisplayComponent|discord.APILabelComponent)[] = []
706
-
707
- for (const component of this.children){
708
- if (component instanceof ODLabelComponent){
709
- //ODLabelComponent (special)
710
- const res = await component.build()
711
- if (res) components.push(res.toJSON())
712
-
713
- }else{
714
- //ODTextComponent (special)
715
- const res = await component.build()
716
- if (res) components.push(res.toJSON())
717
- }
718
- }
719
-
720
- return new discord.ModalBuilder({
721
- components,
722
- title:this.data.title,
723
- customId:this.data.customId
724
- })
725
- }
726
-
727
- /**Set the title of the modal. */
728
- setTitle(title:string){
729
- this.data.title = title
730
- }
731
- /**Set the custom id of this modal. */
732
- setCustomId(id:string|null){
733
- this.data.customId = id ?? undefined
734
- return this
735
- }
736
- }
737
-
738
-
739
- //////////////////////////////////////
740
- // LAYOUT COMPONENT DEFINITIONS //
741
- //////////////////////////////////////
742
-
743
- /**## ODActionRowComponentData `type`
744
- * The configurable settings/options for the `ODActionRowComponent`.
745
- */
746
- export interface ODActionRowComponentData {
747
- //no additional top-level data
748
- }
749
-
750
- /**## ODValidActionRowComponents `type`
751
- * A collection of all valid action row components.
752
- */
753
- export type ODValidActionRowComponents = ODButtonComponent|ODDropdownComponent
754
-
755
- /**## ODActionRowComponent `class`
756
- * An actionrow component which is a container for buttons, a select menu or inputs in a message or modal.
757
- */
758
- export class ODActionRowComponent extends ODGroupComponent<ODActionRowComponentData,ODValidActionRowComponents,discord.ActionRowBuilder<discord.MessageActionRowComponentBuilder>> {
759
- constructor(id:ODValidId,data?:Partial<ODActionRowComponentData>){
760
- const initData: ODActionRowComponentData = {...data}
761
- super(id,"action-row",initData)
762
- }
763
-
764
- async build(){
765
- if (this.children.length < 1) throw new ODSystemError("ODActionRowComponent:build('"+this.id.value+"') => Requires at least one child component.")
766
- if (this.children.length > 5) throw new ODSystemError("ODActionRowComponent:build('"+this.id.value+"') => An action row doesn't support more than 5 components.")
767
-
768
- const components: discord.JSONEncodable<discord.APIComponentInMessageActionRow>[] = []
769
-
770
- for (const component of this.children){
771
- //actionrow ODComponent's
772
- const res = await component.build()
773
- if (res) components.push(res)
774
- }
775
-
776
- return new discord.ActionRowBuilder<discord.MessageActionRowComponentBuilder>({components})
777
- }
778
- }
779
-
780
- /**## ODContainerComponentData `type`
781
- * The configurable settings/options for the `ODContainerComponent`.
782
- */
783
- export interface ODContainerComponentData {
784
- /**The color of this container. */
785
- color?:discord.ColorResolvable,
786
- /**Mark the contents of this container as spoiler. */
787
- spoiler:boolean
788
- }
789
-
790
- /**## ODValidContainerComponents `type`
791
- * A collection of all valid container components.
792
- */
793
- export type ODValidContainerComponents = ODActionRowComponent|ODTextComponent|ODSectionComponent|ODGalleryComponent|ODSeparatorComponent|ODFileComponent
794
-
795
- /**## ODContainerComponent `class`
796
- * An embed-like container for text, titles, buttons, sections, separators and other components.
797
- */
798
- export class ODContainerComponent extends ODGroupComponent<ODContainerComponentData,ODValidContainerComponents,{container:discord.ContainerBuilder,attachments:discord.AttachmentBuilder[]}> {
799
- constructor(id:ODValidId,data?:Partial<ODContainerComponentData>){
800
- const initData: ODContainerComponentData = {spoiler:false,...data}
801
- super(id,"container",initData)
802
- }
803
-
804
- async build(){
805
- if (this.children.length < 1) throw new ODSystemError("ODContainerComponent:build('"+this.id.value+"') => Requires at least one child component.")
806
-
807
- const components: discord.APIComponentInContainer[] = []
808
- const attachments: discord.AttachmentBuilder[] = []
809
-
810
- for (const component of this.children){
811
- if (component instanceof ODFileComponent){
812
- //ODFileComponent (special)
813
- const res = await component.build()
814
- if (res) components.push(res.file.toJSON())
815
- if (res?.attachment) attachments.push(res.attachment)
816
-
817
- }else if (component instanceof ODGalleryComponent){
818
- //ODGalleryComponent (special)
819
- const res = await component.build()
820
- if (res) components.push(res.gallery.toJSON())
821
- if (res?.attachments) attachments.push(...res.attachments)
822
- }else{
823
- //general ODComponent's
824
- const res = await component.build()
825
- if (res) components.push(res.toJSON())
826
- }
827
- }
828
-
829
- return {
830
- container:new discord.ContainerBuilder({
831
- components,
832
- accent_color:this.data.color ? discord.resolveColor(this.data.color) : undefined,
833
- spoiler:this.data.spoiler
834
- }),
835
- attachments
836
- }
837
- }
838
-
839
- /**Set the accent color of this embed-like container. */
840
- setColor(color:discord.ColorResolvable|null){
841
- this.data.color = color ?? undefined
842
- }
843
- /**Mark the contents of this container as spoiler. */
844
- setSpoiler(spoiler:boolean){
845
- this.data.spoiler = spoiler
846
- }
847
- }
848
-
849
-
850
- /**## ODSectionComponentData `type`
851
- * The configurable settings/options for the `ODSectionComponent`.
852
- */
853
- export interface ODSectionComponentData {
854
- /**The accessory component shown on the right side of the section. */
855
- accessory?:ODButtonComponent|ODThumbnailComponent
856
- }
857
-
858
- /**## ODSectionComponent `class`
859
- * A layout component that allows you to contextually associate content with an accessory component.
860
- * - Components: Left
861
- * - Accessory: Right
862
- */
863
- export class ODSectionComponent extends ODGroupComponent<ODSectionComponentData,ODTextComponent,discord.SectionBuilder> {
864
- constructor(id:ODValidId,data?:Partial<ODSectionComponentData>){
865
- const initData: ODSectionComponentData = {...data}
866
- super(id,"section",initData)
867
- }
868
-
869
- async build(){
870
- if (this.children.length < 1) throw new ODSystemError("ODSectionComponent:build('"+this.id.value+"') => Requires at least one child component.")
871
- if (this.children.length > 3) throw new ODSystemError("ODSectionComponent:build('"+this.id.value+"') => A maximum of 3 child components are allowed in a section.")
872
-
873
- const components: discord.APITextDisplayComponent[] = []
874
-
875
- for (const component of this.children){
876
- //section ODComponent's
877
- const res = await component.build()
878
- if (res) components.push(res.toJSON())
879
-
880
- }
881
-
882
- let accessory: discord.APISectionAccessoryComponent|undefined = undefined
883
- if (this.data.accessory){
884
- const accessoryRes = await this.data.accessory.build()
885
- if (accessoryRes) accessory = accessoryRes.toJSON()
886
- }
887
-
888
- return new discord.SectionBuilder({components,accessory})
889
- }
890
-
891
- /**Set the accessory component shown on the right side of the section. */
892
- setAccessory(accessory:ODButtonComponent|ODThumbnailComponent|null){
893
- this.data.accessory = accessory ?? undefined
894
- }
895
- }
896
-
897
- /**## ODLabelComponentData `type`
898
- * The configurable settings/options for the `ODLabelComponent`.
899
- */
900
- export interface ODLabelComponentData {
901
- /**The title for the child component in the modal. */
902
- title:string,
903
- /**An option description for the child component in the modal. */
904
- description?:string
905
- }
906
-
907
- /**## ODValidLabelComponents `type`
908
- * A collection of all valid label components.
909
- */
910
- export type ODValidLabelComponents = ODShortInputComponent|ODParagraphInputComponent|ODDropdownComponent|ODRadioGroupComponent|ODCheckboxGroupComponent|ODCheckboxComponent|ODFileUploadComponent
911
-
912
- /**## ODLabelComponent `class`
913
- * A visual separator between components. The visibility and padding of this separator can be changed.
914
- */
915
- export class ODLabelComponent extends ODParentComponent<ODLabelComponentData,ODValidLabelComponents,discord.LabelBuilder> {
916
- constructor(id:ODValidId,data:Partial<ODLabelComponentData>){
917
- const initData: ODLabelComponentData = {title:"<empty>",...data}
918
- super(id,"label",initData)
919
- }
920
-
921
- async build(){
922
- let component: discord.APIComponentInLabel|undefined = undefined
923
- if (this.child){
924
- const accessoryRes = await this.child.build()
925
- if (accessoryRes) component = accessoryRes.toJSON()
926
- }
927
-
928
- return new discord.LabelBuilder({
929
- label:this.data.title,
930
- description:this.data.description,
931
- component
932
- })
933
- }
934
-
935
- /**Set the title of the child component in the modal. */
936
- setTitle(title:string){
937
- this.data.title = title
938
- }
939
- /**Set the description of the child component in the modal. */
940
- setDescription(description:string|null){
941
- this.data.description = description ?? undefined
942
- }
943
- }
944
-
945
-
946
- /**## ODSeparatorComponentData `type`
947
- * The configurable settings/options for the `ODSeparatorComponent`.
948
- */
949
- export interface ODSeparatorComponentData {
950
- /**Whether a visual divider should be displayed in the component. (Default: `true`) */
951
- divider:boolean,
952
- /**Size of separator padding (Default: `small`) */
953
- spacing:"small"|"large"
954
- }
955
-
956
- /**## ODSeparatorComponent `class`
957
- * A visual separator between components. The visibility and padding of this separator can be changed.
958
- */
959
- export class ODSeparatorComponent extends ODComponent<ODSeparatorComponentData,discord.SeparatorBuilder> {
960
- constructor(id:ODValidId,data:Partial<ODSeparatorComponentData>){
961
- const initData: ODSeparatorComponentData = {divider:true,spacing:"small",...data}
962
- super(id,"separator",initData)
963
- }
964
-
965
- async build(){
966
- return new discord.SeparatorBuilder({
967
- divider:this.data.divider,
968
- spacing:(this.data.spacing == "small") ? discord.SeparatorSpacingSize.Small : discord.SeparatorSpacingSize.Large
969
- })
970
- }
971
-
972
- /**Set whether a visual divider should be displayed in the component. (Default: `true`). */
973
- setDivider(divider:boolean){
974
- this.data.divider = divider
975
- }
976
- /**Set the size of separator padding (Default `small`). */
977
- setSpacing(spacing:"small"|"large"){
978
- this.data.spacing = spacing
979
- }
980
- }
981
-
982
- ///////////////////////////////////////
983
- // CONTENT COMPONENT DEFINITIONS //
984
- ///////////////////////////////////////
985
-
986
- /**## ODTextComponentData `type`
987
- * The configurable settings/options for the `ODTextComponent`.
988
- */
989
- export interface ODTextComponentData {
990
- /**The text to display. */
991
- content:string
992
- }
993
-
994
- /**## ODTextComponent `class`
995
- * A text component which renders markdown text in a message.
996
- */
997
- export class ODTextComponent extends ODComponent<ODTextComponentData,discord.TextDisplayBuilder> {
998
- constructor(id:ODValidId,data:Partial<ODTextComponentData>){
999
- const initData: ODTextComponentData = {content:"",...data}
1000
- super(id,"text",initData)
1001
- }
1002
-
1003
- async build(){
1004
- if (this.data.content.length < 1) throw new ODSystemError("ODTextComponent:build('"+this.id.value+"') => Unable to display text component without contents.")
1005
- return new discord.TextDisplayBuilder({
1006
- content:this.data.content
1007
- })
1008
- }
1009
-
1010
- /**Set the text to display. */
1011
- setContent(value:string){
1012
- this.data.content = value
1013
- }
1014
- }
1015
-
1016
- /**## ODFileComponentData `type`
1017
- * The configurable settings/options for the `ODFileComponent`.
1018
- */
1019
- export interface ODFileComponentData {
1020
- /**The name of this file. */
1021
- name:string,
1022
- /**The description of this file. */
1023
- description?:string,
1024
- /**Should this file be marked as a spoiler? */
1025
- spoiler?:boolean,
1026
- /**The binary/text contents of the file. Ignored when `externalUrl` is used. */
1027
- content?:discord.BufferResolvable,
1028
- /**A URL to an external file or image. When specified, the `content` (setContent) will be ignored. */
1029
- externalUrl?:string
1030
- }
1031
-
1032
- /**## ODFileComponent `class`
1033
- * A file component which adds a file in a message.
1034
- */
1035
- export class ODFileComponent extends ODComponent<ODFileComponentData,{file:discord.FileBuilder,attachment:discord.AttachmentBuilder|null}> {
1036
- constructor(id:ODValidId,data:Partial<ODFileComponentData>){
1037
- const initData: ODFileComponentData = {name:"file.txt",...data}
1038
- super(id,"file",initData)
1039
- }
1040
-
1041
- async build(){
1042
- if (!this.data.content && !this.data.externalUrl) throw new ODSystemError("ODFileComponent:build('"+this.id.value+"') => Unable to display file component without binary or url.")
1043
-
1044
- const attachment = (this.data.content) ? new discord.AttachmentBuilder(this.data.content,{
1045
- name:this.data.name,
1046
- description:this.data.description
1047
- }) : null
1048
-
1049
- return {
1050
- attachment,
1051
- file:new discord.FileBuilder({
1052
- file:{
1053
- url:(this.data.externalUrl ?? "attachment://"+this.data.name)
1054
- },
1055
- spoiler:this.data.spoiler
1056
- })
1057
- }
1058
- }
1059
-
1060
- /**Set the filename + extension. */
1061
- setName(value:string){
1062
- this.data.name = value
1063
- }
1064
- /**Set the file description. */
1065
- setDescription(value:string|null){
1066
- this.data.description = value ?? undefined
1067
- }
1068
- /**Set the text/binary contents of the file. */
1069
- setContent(value:discord.BufferResolvable|null){
1070
- this.data.content = value ?? undefined
1071
- }
1072
- /**Set a URL to an external file or image. When used, `setContent()` will be ignored! */
1073
- setExternalUrl(value:string|null){
1074
- this.data.externalUrl = value ?? undefined
1075
- }
1076
- /**Mark the file as spoiler. */
1077
- setSpoiler(value:boolean){
1078
- this.data.spoiler = value
1079
- }
1080
- }
1081
-
1082
- /**## ODGalleryComponentData `type`
1083
- * The configurable settings/options for the `ODGalleryComponent`.
1084
- */
1085
- export interface ODGalleryComponentData {
1086
- //no additional top-level data
1087
- }
1088
-
1089
- /**## ODGalleryComponent `class`
1090
- * A gallery component which renders a grid of media items (images/videos) in a message.
1091
- * Add items to this gallery using `addComponent()`.
1092
- */
1093
- export class ODGalleryComponent extends ODGroupComponent<ODGalleryComponentData,ODFileComponent,{gallery:discord.MediaGalleryBuilder,attachments:discord.AttachmentBuilder[]}> {
1094
- constructor(id:ODValidId,data?:Partial<ODGalleryComponentData>){
1095
- const initData: ODGalleryComponentData = {...data}
1096
- super(id,"gallery",initData)
1097
- }
1098
-
1099
- async build(){
1100
- if (this.children.length < 1) throw new ODSystemError("ODGalleryComponent:build('"+this.id.value+"') => Requires at least one child component.")
1101
-
1102
- const gallery = new discord.MediaGalleryBuilder()
1103
- const attachments: discord.AttachmentBuilder[] = []
1104
-
1105
- for (const file of this.children){
1106
- if (!file.data.content && !file.data.externalUrl) continue
1107
- if (file.data.content) attachments.push(new discord.AttachmentBuilder(file.data.content,{
1108
- name:file.data.name,
1109
- description:file.data.description
1110
- }))
1111
- gallery.addItems(new discord.MediaGalleryItemBuilder({
1112
- description:file.data.description,
1113
- spoiler:file.data.spoiler,
1114
- media:{
1115
- url:(file.data.externalUrl ?? "attachment://"+file.data.name)
1116
- }
1117
- }))
1118
- }
1119
-
1120
- return {gallery,attachments}
1121
- }
1122
- }
1123
-
1124
- /**## ODThumbnailComponentData `type`
1125
- * The configurable settings/options for the `ODThumbnailComponent`.
1126
- */
1127
- export interface ODThumbnailComponentData {
1128
- /**The URL of the thumbnail image. Can be an external URL or `attachment://filename.ext`. */
1129
- url:string,
1130
- /**The alt text/description of the thumbnail image. */
1131
- description?:string,
1132
- /**Should this thumbnail be marked as a spoiler? */
1133
- spoiler?:boolean
1134
- }
1135
-
1136
- /**## ODThumbnailComponent `class`
1137
- * A thumbnail component which renders a small image as an accessory inside an `ODSectionComponent`.
1138
- * This component must be used via `ODSectionComponent.setComponent()`
1139
- */
1140
- export class ODThumbnailComponent extends ODComponent<ODThumbnailComponentData,discord.ThumbnailBuilder> {
1141
- constructor(id:ODValidId,data:Partial<ODThumbnailComponentData>){
1142
- const initData: ODThumbnailComponentData = {url:"",...data}
1143
- super(id,"thumbnail",initData)
1144
- }
1145
-
1146
- async build(){
1147
- if (this.data.url.length < 1) throw new ODSystemError("ODThumbnailComponent:build('"+this.id.value+"') => Thumbnail component requires an image URL.")
1148
-
1149
- return new discord.ThumbnailBuilder({
1150
- media:{ url:this.data.url },
1151
- description:this.data.description,
1152
- spoiler:this.data.spoiler
1153
- })
1154
- }
1155
-
1156
- /**Set the URL of the thumbnail image. */
1157
- setUrl(value:string){
1158
- this.data.url = value
1159
- }
1160
- /**Set the alt text/description of the thumbnail image. */
1161
- setDescription(value:string|null){
1162
- this.data.description = value ?? undefined
1163
- }
1164
- /**Mark the thumbnail as a spoiler. */
1165
- setSpoiler(value:boolean){
1166
- this.data.spoiler = value
1167
- }
1168
- }
1169
-
1170
- /**## ODContentComponentData `type`
1171
- * The configurable settings/options for the `ODContentComponent`.
1172
- */
1173
- export interface ODContentComponentData {
1174
- /**The text to display. */
1175
- content:string
1176
- }
1177
-
1178
- /**## ODContentComponent `class`
1179
- * A text component which renders markdown text in a message without `Components V2` enabled. (Old behaviour)
1180
- */
1181
- export class ODContentComponent extends ODComponent<ODContentComponentData,{content:string}> {
1182
- constructor(id:ODValidId,data:Partial<ODContentComponentData>){
1183
- const initData: ODContentComponentData = {content:"",...data}
1184
- super(id,"simple-content",initData)
1185
- }
1186
-
1187
- async build(){
1188
- if (this.data.content.length < 1) throw new ODSystemError("ODContentComponent:build('"+this.id.value+"') => Unable to display content component without contents.")
1189
- return {
1190
- content:this.data.content
1191
- }
1192
- }
1193
-
1194
- /**Set the text to display. */
1195
- setContent(value:string){
1196
- this.data.content = value
1197
- }
1198
- }
1199
-
1200
-
1201
- /**## ODEmbedComponentData `type`
1202
- * The configurable settings/options for the `ODEmbedComponent`.
1203
- */
1204
- export interface ODEmbedComponentData {
1205
- /**The title of the embed. */
1206
- title?:string,
1207
- /**The color of the embed. */
1208
- color?:discord.ColorResolvable,
1209
- /**The url of the embed. */
1210
- url?:string,
1211
- /**The description of the embed. */
1212
- description?:string,
1213
- /**The author text of the embed. */
1214
- authorText?:string,
1215
- /**The author image of the embed. */
1216
- authorImage?:string,
1217
- /**The author url of the embed. */
1218
- authorUrl?:string,
1219
- /**The footer text of the embed. */
1220
- footerText?:string,
1221
- /**The footer image of the embed. */
1222
- footerImage?:string,
1223
- /**The image of the embed. */
1224
- image?:string,
1225
- /**The thumbnail of the embed. */
1226
- thumbnail?:string,
1227
- /**The fields of the embed. */
1228
- fields?:ODInterfaceWithPartialProperty<discord.EmbedField,"inline">[],
1229
- /**The timestamp of the embed. */
1230
- timestamp?:number|Date
1231
- }
1232
-
1233
- /**## ODEmbedComponent `class`
1234
- * An embed component which renders an embed in a message without `Components V2` enabled. (Old behaviour)
1235
- */
1236
- export class ODEmbedComponent extends ODComponent<ODEmbedComponentData,discord.EmbedBuilder> {
1237
- constructor(id:ODValidId,data:Partial<ODEmbedComponentData>){
1238
- const initData: ODEmbedComponentData = {...data}
1239
- super(id,"simple-embed",initData)
1240
- }
1241
-
1242
- async build(){
1243
- if (this.data.title && this.data.title.length > 256) throw new ODSystemError("ODEmbedComponent:build('"+this.id.value+"') => An embed title can't exceed 256 characters.")
1244
- if (this.data.description && this.data.description.length > 4096) throw new ODSystemError("ODEmbedComponent:build('"+this.id.value+"') => An embed description can't exceed 4096 characters.")
1245
- if (this.data.fields && this.data.fields.length > 25) throw new ODSystemError("ODEmbedComponent:build('"+this.id.value+"') => An embed can't contain more than 25 fields.")
1246
- if (this.data.footerText && this.data.footerText.length > 2048) throw new ODSystemError("ODEmbedComponent:build('"+this.id.value+"') => An embed footer can't exceed 2048 characters.")
1247
- if (this.data.authorText && this.data.authorText.length > 256) throw new ODSystemError("ODEmbedComponent:build('"+this.id.value+"') => An embed author can't exceed 256 characters.")
1248
-
1249
- return new discord.EmbedBuilder({
1250
- title:this.data.title,
1251
- color:(this.data.color) ? discord.resolveColor(this.data.color) : undefined,
1252
- url:this.data.url,
1253
- description:this.data.description,
1254
- author:(this.data.authorText) ? {
1255
- name:this.data.authorText,
1256
- icon_url:this.data.authorImage,
1257
- url:this.data.authorUrl
1258
- } : undefined,
1259
- footer:(this.data.footerText) ? {
1260
- text:this.data.footerText,
1261
- icon_url:this.data.footerImage
1262
- } : undefined,
1263
- image:(this.data.image) ? {
1264
- url:this.data.image
1265
- } : undefined,
1266
- thumbnail:(this.data.thumbnail) ? {
1267
- url:this.data.thumbnail
1268
- } : undefined,
1269
- fields:this.data.fields,
1270
- timestamp:(this.data.timestamp) ? new Date(this.data.timestamp).toISOString() : undefined
1271
- })
1272
- }
1273
-
1274
- /**Set the title of this embed */
1275
- setTitle(title:string|null){
1276
- this.data.title = title ?? undefined
1277
- return this
1278
- }
1279
- /**Set the color of this embed */
1280
- setColor(color:discord.ColorResolvable|null){
1281
- this.data.color = color ?? undefined
1282
- return this
1283
- }
1284
- /**Set the url of this embed */
1285
- setUrl(url:string|null){
1286
- this.data.url = url ?? undefined
1287
- return this
1288
- }
1289
- /**Set the description of this embed */
1290
- setDescription(description:string|null){
1291
- this.data.description = description ?? undefined
1292
- return this
1293
- }
1294
- /**Set the author of this embed */
1295
- setAuthor(text:string|null, image?:string|null, url?:string|null){
1296
- this.data.authorText = text ?? undefined
1297
- this.data.authorImage = image ?? undefined
1298
- this.data.authorUrl = url ?? undefined
1299
- return this
1300
- }
1301
- /**Set the footer of this embed */
1302
- setFooter(text:string|null, image?:string|null){
1303
- this.data.footerText = text ?? undefined
1304
- this.data.footerImage = image ?? undefined
1305
- return this
1306
- }
1307
- /**Set the image of this embed */
1308
- setImage(image:string|null){
1309
- this.data.image = image ?? undefined
1310
- return this
1311
- }
1312
- /**Set the thumbnail of this embed */
1313
- setThumbnail(thumbnail:string|null){
1314
- this.data.thumbnail = thumbnail ?? undefined
1315
- return this
1316
- }
1317
- /**Set the fields of this embed */
1318
- setFields(fields:ODInterfaceWithPartialProperty<discord.EmbedField,"inline">[]){
1319
- //Check field properties
1320
- for (const [index,field] of fields.entries()){
1321
- if (field.value.length >= 1024) throw new ODSystemError("ODEmbedComponent:build('"+this.id.value+"') => field "+index+" reached 1024 character limit!")
1322
- if (field.name.length >= 256) throw new ODSystemError("ODEmbedComponent:build('"+this.id.value+"') => field "+index+" reached 256 name character limit!")
1323
- }
1324
- this.data.fields = fields
1325
- return this
1326
- }
1327
- /**Add fields to this embed */
1328
- addFields(...fields:ODInterfaceWithPartialProperty<discord.EmbedField,"inline">[]){
1329
- //Check field properties
1330
- for (const [index,field] of fields.entries()){
1331
- if (field.value.length >= 1024) throw new ODSystemError("ODEmbedComponent:build('"+this.id.value+"') => field "+index+" reached 1024 character limit!")
1332
- if (field.name.length >= 256) throw new ODSystemError("ODEmbedComponent:build('"+this.id.value+"') => field "+index+" reached 256 name character limit!")
1333
- }
1334
-
1335
- if (!this.data.fields) this.data.fields = []
1336
- this.data.fields.push(...fields)
1337
- return this
1338
- }
1339
- /**Clear all fields from this embed */
1340
- clearFields(){
1341
- this.data.fields = []
1342
- return this
1343
- }
1344
- /**Set the timestamp of this embed. When set to `true`, the current timestamp is used. */
1345
- setTimestamp(timestamp:number|Date|true|null){
1346
- if (timestamp === true) this.data.timestamp = new Date()
1347
- else this.data.timestamp = timestamp ?? undefined
1348
- return this
1349
- }
1350
- }
1351
-
1352
- /**## ODPollComponentData `type`
1353
- * The configurable settings/options for the `ODPollComponent`.
1354
- */
1355
- export interface ODPollComponentData {
1356
- /**The poll question. */
1357
- question:string,
1358
- /**The duration of the poll in hours. */
1359
- durationHours:number,
1360
- /**Available poll answers. */
1361
- answers:discord.PollAnswerData[],
1362
- /**Allow selecting multiple answers. */
1363
- allowMultiSelect:boolean
1364
- }
1365
-
1366
- /**## ODPollComponent `class`
1367
- * A poll component which adds a poll to a message without `Components V2` enabled. (Old behaviour)
1368
- */
1369
- export class ODPollComponent extends ODComponent<ODPollComponentData,discord.PollData> {
1370
- constructor(id:ODValidId,data:Partial<ODPollComponentData>){
1371
- const initData: ODPollComponentData = {question:"<empty>",durationHours:1,allowMultiSelect:false,answers:[],...data}
1372
- super(id,"simple-poll",initData)
1373
- }
1374
-
1375
- async build(){
1376
- if (this.data.question.length < 1) throw new ODSystemError("ODPollComponent:build('"+this.id.value+"') => Please provide a valid poll question.")
1377
- if (this.data.answers.length < 1) throw new ODSystemError("ODPollComponent:build('"+this.id.value+"') => Please provide at least one answer to the poll.")
1378
- return {
1379
- layoutType:discord.PollLayoutType.Default,
1380
- allowMultiselect:this.data.allowMultiSelect,
1381
- duration:this.data.durationHours,
1382
- question:{text:this.data.question},
1383
- answers:this.data.answers
1384
- }
1385
- }
1386
-
1387
- /**Set the poll question. */
1388
- setQuestion(question:string){
1389
- this.data.question = question
1390
- }
1391
- /**Set the poll duration in hours. */
1392
- setDurationHours(duration:number){
1393
- this.data.durationHours = duration
1394
- }
1395
- /**Allow selecting multiple answers. */
1396
- setMultiSelect(multi:boolean){
1397
- this.data.allowMultiSelect = multi
1398
- }
1399
- /**Set the poll answers. */
1400
- setAnswers(answers:discord.PollAnswerData[]){
1401
- this.data.answers = answers
1402
- }
1403
- /**Add additional poll answers. */
1404
- addAnswers(...answers:discord.PollAnswerData[]){
1405
- this.data.answers.push(...answers)
1406
- }
1407
- }
1408
-
1409
- ///////////////////////////////////////////
1410
- // INTERACTIVE COMPONENT DEFINITIONS //
1411
- ///////////////////////////////////////////
1412
-
1413
-
1414
- /**## ODButtonComponentData `type`
1415
- * The configurable settings/options for the `ODButtonComponent`.
1416
- */
1417
- export interface ODButtonComponentData {
1418
- /**The custom id of this button. Ignored when `url` is specified. */
1419
- customId?:string,
1420
- /**The url of this button. Disables interactions & customId */
1421
- url?:string,
1422
- /**The button color. Ignored when `url` is specified. */
1423
- color:ODValidButtonColor,
1424
- /**The button label */
1425
- label?:string,
1426
- /**The button emoji */
1427
- emoji?:string,
1428
- /**Is the button disabled? */
1429
- disabled:boolean
1430
- }
1431
-
1432
- /**## ODButtonComponent `class`
1433
- * A button component which renders an interactive button inside the message.
1434
- * A reply can be sent using Open Discord responders.
1435
- */
1436
- export class ODButtonComponent extends ODComponent<ODButtonComponentData,discord.ButtonBuilder> {
1437
- constructor(id:ODValidId,data:Partial<ODButtonComponentData>){
1438
- const initData: ODButtonComponentData = {color:"gray",disabled:false,...data}
1439
- super(id,"button",initData)
1440
- }
1441
-
1442
- async build(){
1443
- if (!this.data.emoji && !this.data.label) throw new ODSystemError("ODButtonComponent:build('"+this.id.value+"') => A button must include at least one label or emoji.")
1444
- if (this.data.customId && this.data.customId.length > 100) throw new ODSystemError("ODButtonComponent:build('"+this.id.value+"') => A custom ID '"+this.data.customId+"' must be shorter than 100 characters.")
1445
-
1446
- return new discord.ButtonBuilder({
1447
- customId:(!this.data.url) ? this.data.customId : undefined,
1448
- label:this.data.label,
1449
- emoji:this.data.emoji ? discord.resolvePartialEmoji(this.data.emoji) : undefined,
1450
- disabled:this.data.disabled,
1451
- url:(this.data.url) ? this.data.url : undefined,
1452
- style:this.getButtonStyle(),
1453
- })
1454
- }
1455
-
1456
- /**Get the `discord.ButtonStyle` for the specified `ODValidButtonColor` */
1457
- protected getButtonStyle(): discord.ButtonStyle {
1458
- if (this.data.url) return discord.ButtonStyle.Link
1459
- else if (this.data.color == "blue") return discord.ButtonStyle.Primary
1460
- else if (this.data.color == "green") return discord.ButtonStyle.Success
1461
- else if (this.data.color == "red") return discord.ButtonStyle.Danger
1462
- else return discord.ButtonStyle.Secondary
1463
- }
1464
-
1465
- /**Set the custom id of this button. Ignored when `setUrl()` is used. */
1466
- setCustomId(id:string|null){
1467
- this.data.customId = id ?? undefined
1468
- return this
1469
- }
1470
- /**Set the url of this button. */
1471
- setUrl(url:string|null){
1472
- this.data.url = url ?? undefined
1473
- return this
1474
- }
1475
- /**Set the color of this button. Ignored when `setUrl()` is used. */
1476
- setColor(color:ODValidButtonColor){
1477
- this.data.color = color
1478
- return this
1479
- }
1480
- /**Set the label of this button. */
1481
- setLabel(label:string|null){
1482
- this.data.label = label ?? undefined
1483
- return this
1484
- }
1485
- /**Set the emoji of this button. */
1486
- setEmoji(emoji:string|null){
1487
- this.data.emoji = emoji ?? undefined
1488
- return this
1489
- }
1490
- /**Disable this button. */
1491
- setDisabled(disabled:boolean){
1492
- this.data.disabled = disabled
1493
- return this
1494
- }
1495
- }
1496
-
1497
-
1498
- /**## ODShortInputComponentData `type`
1499
- * The configurable settings/options for the `ODShortInputComponent`.
1500
- */
1501
- export interface ODShortInputComponentData {
1502
- /**The custom id of this modal text input. */
1503
- customId?:string
1504
- /**The min length of this modal text input. */
1505
- minLength?:number,
1506
- /**The max length of this modal text input. */
1507
- maxLength?:number,
1508
- /**Is this modal text input required? */
1509
- required:boolean,
1510
- /**The placeholder of this modal text input. */
1511
- placeholder?:string,
1512
- /**The initial value of this modal text input. */
1513
- initialValue?:string
1514
- }
1515
-
1516
- /**## ODShortInputComponent `class`
1517
- * A short text input component for modals.
1518
- * It must be placed inside an `ODLabelComponent`.
1519
- */
1520
- export class ODShortInputComponent extends ODComponent<ODShortInputComponentData,discord.TextInputBuilder> {
1521
- constructor(id:ODValidId,data:Partial<ODShortInputComponentData>){
1522
- const initData: ODShortInputComponentData = {required:false,...data}
1523
- super(id,"short-input",initData)
1524
- }
1525
-
1526
- async build(){
1527
- return new discord.TextInputBuilder({
1528
- style:discord.TextInputStyle.Short,
1529
- customId:this.data.customId,
1530
- minLength:this.data.minLength,
1531
- maxLength:this.data.maxLength,
1532
- required:this.data.required,
1533
- placeholder:this.data.placeholder,
1534
- value:this.data.initialValue
1535
- })
1536
- }
1537
-
1538
- /**Set the custom id of this modal text input. */
1539
- setCustomId(id:string|null){
1540
- this.data.customId = id ?? undefined
1541
- return this
1542
- }
1543
- /**Set the minimum amount of characters of this modal text input. */
1544
- setMinLength(length:number|null){
1545
- this.data.minLength = length ?? undefined
1546
- return this
1547
- }
1548
- /**Set the maximum amount of characters of this modal text input. */
1549
- setMaxLength(length:number|null){
1550
- this.data.maxLength = length ?? undefined
1551
- return this
1552
- }
1553
- /**Set the placeholder of this modal text input. */
1554
- setPlaceholder(placeholder:string|null){
1555
- this.data.placeholder = placeholder ?? undefined
1556
- return this
1557
- }
1558
- /**Set the initial value of this modal text input. */
1559
- setInitialValue(initialValue:string|null){
1560
- this.data.initialValue = initialValue ?? undefined
1561
- return this
1562
- }
1563
- /**Mark this modal text input as required. */
1564
- setRequired(required:boolean){
1565
- this.data.required = required
1566
- return this
1567
- }
1568
- }
1569
-
1570
- /**## ODParagraphInputComponentData `type`
1571
- * The configurable settings/options for the `ODParagraphInputComponent`.
1572
- */
1573
- export interface ODParagraphInputComponentData {
1574
- /**The custom id of this modal text input. */
1575
- customId?:string
1576
- /**The min length of this modal text input. */
1577
- minLength?:number,
1578
- /**The max length of this modal text input. */
1579
- maxLength?:number,
1580
- /**Is this modal text input required? */
1581
- required:boolean,
1582
- /**The placeholder of this modal text input. */
1583
- placeholder?:string,
1584
- /**The initial value of this modal text input. */
1585
- initialValue?:string
1586
- }
1587
-
1588
- /**## ODParagraphInputComponent `class`
1589
- * A paragraph text input component for modals.
1590
- * It must be placed inside an `ODLabelComponent`.
1591
- */
1592
- export class ODParagraphInputComponent extends ODComponent<ODParagraphInputComponentData,discord.TextInputBuilder> {
1593
- constructor(id:ODValidId,data:Partial<ODParagraphInputComponentData>){
1594
- const initData: ODParagraphInputComponentData = {required:false,...data}
1595
- super(id,"paragraph-input",initData)
1596
- }
1597
-
1598
- async build(){
1599
- return new discord.TextInputBuilder({
1600
- style:discord.TextInputStyle.Paragraph,
1601
- customId:this.data.customId,
1602
- minLength:this.data.minLength,
1603
- maxLength:this.data.maxLength,
1604
- required:this.data.required,
1605
- placeholder:this.data.placeholder,
1606
- value:this.data.initialValue
1607
- })
1608
- }
1609
-
1610
- /**Set the custom id of this modal text input. */
1611
- setCustomId(id:string|null){
1612
- this.data.customId = id ?? undefined
1613
- return this
1614
- }
1615
- /**Set the minimum amount of characters of this modal text input. */
1616
- setMinLength(length:number|null){
1617
- this.data.minLength = length ?? undefined
1618
- return this
1619
- }
1620
- /**Set the maximum amount of characters of this modal text input. */
1621
- setMaxLength(length:number|null){
1622
- this.data.maxLength = length ?? undefined
1623
- return this
1624
- }
1625
- /**Set the placeholder of this modal text input. */
1626
- setPlaceholder(placeholder:string|null){
1627
- this.data.placeholder = placeholder ?? undefined
1628
- return this
1629
- }
1630
- /**Set the initial value of this modal text input. */
1631
- setInitialValue(initialValue:string|null){
1632
- this.data.initialValue = initialValue ?? undefined
1633
- return this
1634
- }
1635
- /**Mark this modal text input as required. */
1636
- setRequired(required:boolean){
1637
- this.data.required = required
1638
- return this
1639
- }
1640
- }
1641
-
1642
-
1643
- /**## ODDropdownComponentData `type`
1644
- * The configurable settings/options for the `ODDropdownComponent`.
1645
- */
1646
- export interface ODDropdownComponentData {
1647
- /**The type of this dropdown. */
1648
- type:"string"|"role"|"channel"|"user"|"mentionable",
1649
- /**The custom id of this dropdown. */
1650
- customId?:string,
1651
- /**The placeholder of this dropdown. */
1652
- placeholder?:string,
1653
- /**The minimum amount of items to be selected in this dropdown. */
1654
- minValues?:number,
1655
- /**The maximum amount of items to be selected in this dropdown. */
1656
- maxValues?:number,
1657
- /**Is this dropdown disabled? */
1658
- disabled?:boolean,
1659
-
1660
- /**Allowed channel types when the type is "channel" */
1661
- channelTypes?:discord.ChannelType[]
1662
- /**The options when the type is "string" */
1663
- options?:discord.SelectMenuComponentOptionData[],
1664
- /**The options when the type is "user" */
1665
- users?:discord.User[],
1666
- /**The options when the type is "role" */
1667
- roles?:discord.Role[],
1668
- /**The options when the type is "channel" */
1669
- channels?:discord.Channel[],
1670
- /**The options when the type is "mentionable" */
1671
- mentionables?:(discord.User|discord.Role)[],
1672
- }
1673
-
1674
- /**## ODDropdownComponent `class`
1675
- * A dropdown component which renders an interactive dropdown inside the message/modal.
1676
- * A reply can be sent using Open Discord responders.
1677
- */
1678
- export class ODDropdownComponent extends ODComponent<ODDropdownComponentData,discord.BaseSelectMenuBuilder<discord.APISelectMenuComponent>> {
1679
- constructor(id:ODValidId,data:Partial<ODDropdownComponentData>){
1680
- const initData: ODDropdownComponentData = {type:"string",...data}
1681
- super(id,"dropdown",initData)
1682
- }
1683
-
1684
- async build(){
1685
- const genericOpts = {
1686
- customId:this.data.customId,
1687
- disabled:this.data.disabled,
1688
- placeholder:this.data.placeholder,
1689
- minValues:this.data.minValues,
1690
- maxValues:this.data.maxValues,
1691
- }
1692
-
1693
- if (this.data.type == "string"){
1694
- if (!this.data.options || this.data.options.length < 1) throw new ODSystemError("ODDropdownComponent:build('"+this.id.value+"') => Please provide at least one string option using setOptions().")
1695
- return new discord.StringSelectMenuBuilder({
1696
- ...genericOpts,
1697
- options:this.data.options
1698
- })
1699
- }else if (this.data.type == "user"){
1700
- if (!this.data.users || this.data.users.length < 1) throw new ODSystemError("ODDropdownComponent:build('"+this.id.value+"') => Please provide at least one user option using setUsers().")
1701
- return new discord.UserSelectMenuBuilder({
1702
- ...genericOpts,
1703
- defaultValues:this.data.users.map((u) => ({id:u.id,type:discord.SelectMenuDefaultValueType.User}))
1704
- })
1705
- }else if (this.data.type == "role"){
1706
- if (!this.data.roles || this.data.roles.length < 1) throw new ODSystemError("ODDropdownComponent:build('"+this.id.value+"') => Please provide at least one role option using setRoles().")
1707
- return new discord.RoleSelectMenuBuilder({
1708
- ...genericOpts,
1709
- defaultValues:this.data.roles.map((r) => ({id:r.id,type:discord.SelectMenuDefaultValueType.Role}))
1710
- })
1711
- }else if (this.data.type == "channel"){
1712
- if (!this.data.channels || this.data.channels.length < 1) throw new ODSystemError("ODDropdownComponent:build('"+this.id.value+"') => Please provide at least one channel option using setChannels().")
1713
- return new discord.ChannelSelectMenuBuilder({
1714
- ...genericOpts,
1715
- channelTypes:this.data.channelTypes,
1716
- defaultValues:this.data.channels.map((c) => ({id:c.id,type:discord.SelectMenuDefaultValueType.Channel}))
1717
- })
1718
- }else if (this.data.type == "mentionable"){
1719
- if (!this.data.mentionables || this.data.mentionables.length < 1) throw new ODSystemError("ODDropdownComponent:build('"+this.id.value+"') => Please provide at least one role/user option using setMentionables().")
1720
- return new discord.MentionableSelectMenuBuilder({
1721
- ...genericOpts,
1722
- defaultValues:this.data.mentionables.map((m) => (m instanceof discord.User ? {id:m.id,type:discord.SelectMenuDefaultValueType.User} : {id:m.id,type:discord.SelectMenuDefaultValueType.Role}))
1723
- })
1724
- }else throw new ODSystemError("ODDropdownComponent:build('"+this.id.value+"') => Please set the dropdown type to one of the following: string, user, role, channel, mentionable.")
1725
- }
1726
-
1727
- /**Set the custom id of this dropdown. */
1728
- setCustomId(id:string|null){
1729
- this.data.customId = id ?? undefined
1730
- return this
1731
- }
1732
- /**Set the type of this dropdown. */
1733
- setType(type:"string"|"role"|"channel"|"user"|"mentionable"){
1734
- this.data.type = type
1735
- return this
1736
- }
1737
- /**Set the minimum selection amount of this dropdown. */
1738
- setMinValues(amount:number|null){
1739
- this.data.minValues = amount ?? undefined
1740
- return this
1741
- }
1742
- /**Set the maximum selection amount of this dropdown. */
1743
- setMaxValues(amount:number|null){
1744
- this.data.maxValues = amount ?? undefined
1745
- return this
1746
- }
1747
- /**Set the placeholder of this dropdown. */
1748
- setPlaceholder(placeholder:string|null){
1749
- this.data.placeholder = placeholder ?? undefined
1750
- return this
1751
- }
1752
- /**Disable this dropdown. */
1753
- setDisabled(disabled:boolean){
1754
- this.data.disabled = disabled
1755
- return this
1756
- }
1757
- /**Set the available channel types of this dropdown. */
1758
- setChannelTypes(channelTypes:discord.ChannelType[]){
1759
- this.data.channelTypes = channelTypes
1760
- return this
1761
- }
1762
- /**Set the options of this dropdown (when `type == "string"`) */
1763
- setOptions(options:discord.SelectMenuComponentOptionData[]){
1764
- this.data.options = options
1765
- return this
1766
- }
1767
- /**Set the users of this dropdown (when `type == "user"`) */
1768
- setUsers(users:discord.User[]){
1769
- this.data.users = users
1770
- return this
1771
- }
1772
- /**Set the roles of this dropdown (when `type == "role"`) */
1773
- setRoles(roles:discord.Role[]){
1774
- this.data.roles = roles
1775
- return this
1776
- }
1777
- /**Set the channels of this dropdown (when `type == "channel"`) */
1778
- setChannels(channels:discord.Channel[]){
1779
- this.data.channels = channels
1780
- return this
1781
- }
1782
- /**Set the mentionables of this dropdown (when `type == "mentionable"`) */
1783
- setMentionables(mentionables:(discord.User|discord.Role)[]){
1784
- this.data.mentionables = mentionables
1785
- return this
1786
- }
1787
- }
1788
-
1789
-
1790
- /**## ODRadioGroupComponentData `type`
1791
- * The configurable settings/options for the `ODRadioGroupComponent`.
1792
- */
1793
- export interface ODRadioGroupComponentData {
1794
- /**The custom id of this radio group. */
1795
- customId?:string,
1796
- /**Is this radio group required? (At least one option must be selected) */
1797
- required:boolean,
1798
- /**The available radio options. (min 2, max 10) */
1799
- options:discord.APIRadioGroupOption[]
1800
- }
1801
-
1802
- /**## ODRadioGroupComponent `class`
1803
- * A radio group component which renders an interactive radio group input inside a modal.
1804
- */
1805
- export class ODRadioGroupComponent extends ODComponent<ODRadioGroupComponentData,discord.RadioGroupBuilder> {
1806
- constructor(id:ODValidId,data:Partial<ODRadioGroupComponentData>){
1807
- const initData: ODRadioGroupComponentData = {required:false,options:[],...data}
1808
- super(id,"radio-group",initData)
1809
- }
1810
-
1811
- async build(){
1812
- if (!this.data.options || this.data.options.length < 2) throw new ODSystemError("ODRadioGroupComponent:build('"+this.id.value+"') => Please provide at least 2 radio options using setOptions().")
1813
-
1814
- return new discord.RadioGroupBuilder({
1815
- custom_id:this.data.customId,
1816
- required:this.data.required,
1817
- options:this.data.options
1818
- })
1819
- }
1820
-
1821
- /**Set the custom id of this radio group. */
1822
- setCustomId(id:string|null){
1823
- this.data.customId = id ?? undefined
1824
- return this
1825
- }
1826
- /**Mark this radio group as required (At least one option must be selected). */
1827
- setRequired(required:boolean){
1828
- this.data.required = required
1829
- return this
1830
- }
1831
- /**Set the available radio options (min 2, max 10) */
1832
- setOptions(options:discord.APIRadioGroupOption[]){
1833
- this.data.options = options
1834
- return this
1835
- }
1836
- }
1837
-
1838
-
1839
- /**## ODCheckboxGroupComponentData `type`
1840
- * The configurable settings/options for the `ODCheckboxGroupComponent`.
1841
- */
1842
- export interface ODCheckboxGroupComponentData {
1843
- /**The custom id of this checkbox group. */
1844
- customId?:string,
1845
- /**Is this checkbox group required? (At least one option must be selected) */
1846
- required:boolean,
1847
- /**The available checkbox options. (min 1, max 10) */
1848
- options:discord.APICheckboxGroupOption[],
1849
- /**The minimum amount of checkboxes to be selected. */
1850
- minValues?:number,
1851
- /**The maximum amount of checkboxes to be selected. */
1852
- maxValues?:number
1853
- }
1854
-
1855
- /**## ODCheckboxGroupComponent `class`
1856
- * A checkbox group component which renders an interactive checkbox group input inside a modal.
1857
- */
1858
- export class ODCheckboxGroupComponent extends ODComponent<ODCheckboxGroupComponentData,discord.CheckboxGroupBuilder> {
1859
- constructor(id:ODValidId,data:Partial<ODCheckboxGroupComponentData>){
1860
- const initData: ODCheckboxGroupComponentData = {required:false,options:[],...data}
1861
- super(id,"checkbox-group",initData)
1862
- }
1863
-
1864
- async build(){
1865
- if (!this.data.options || this.data.options.length < 2) throw new ODSystemError("ODCheckboxGroupComponent:build('"+this.id.value+"') => Please provide at least 2 radio options using setOptions().")
1866
-
1867
- return new discord.CheckboxGroupBuilder({
1868
- custom_id:this.data.customId,
1869
- required:this.data.required,
1870
- options:this.data.options,
1871
- min_values:this.data.minValues,
1872
- max_values:this.data.maxValues
1873
- })
1874
- }
1875
-
1876
- /**Set the custom id of this checkbox group. */
1877
- setCustomId(id:string|null){
1878
- this.data.customId = id ?? undefined
1879
- return this
1880
- }
1881
- /**Mark this checkbox group as required (At least one option must be selected). */
1882
- setRequired(required:boolean){
1883
- this.data.required = required
1884
- return this
1885
- }
1886
- /**Set the available checkbox options (min 2, max 10) */
1887
- setOptions(options:discord.APICheckboxGroupOption[]){
1888
- this.data.options = options
1889
- return this
1890
- }
1891
- /**Set the minimum amount of selected checkboxes. */
1892
- setMinValues(amount:number|null){
1893
- this.data.minValues = amount ?? undefined
1894
- return this
1895
- }
1896
- /**Set the maximum amount of selected checkboxes. */
1897
- setMaxValues(amount:number|null){
1898
- this.data.maxValues = amount ?? undefined
1899
- return this
1900
- }
1901
- }
1902
-
1903
-
1904
- /**## ODCheckboxComponentData `type`
1905
- * The configurable settings/options for the `ODCheckboxComponent`.
1906
- */
1907
- export interface ODCheckboxComponentData {
1908
- /**The custom id of this checkbox. */
1909
- customId?:string,
1910
- /**Is this checkbox enabled by default? */
1911
- default:boolean,
1912
- }
1913
-
1914
- /**## ODCheckboxComponent `class`
1915
- * A checkbox component which renders an interactive checkbox input inside a modal.
1916
- * The label & description should be set via an `ODLabelComponent`
1917
- */
1918
- export class ODCheckboxComponent extends ODComponent<ODCheckboxComponentData,discord.CheckboxBuilder> {
1919
- constructor(id:ODValidId,data:Partial<ODCheckboxComponentData>){
1920
- const initData: ODCheckboxComponentData = {default:false,...data}
1921
- super(id,"checkbox",initData)
1922
- }
1923
-
1924
- async build(){
1925
- return new discord.CheckboxBuilder({
1926
- custom_id:this.data.customId,
1927
- default:this.data.default
1928
- })
1929
- }
1930
-
1931
- /**Set the custom id of this checkbox. */
1932
- setCustomId(id:string|null){
1933
- this.data.customId = id ?? undefined
1934
- return this
1935
- }
1936
- /**Mark this checkbox as enabled by default. */
1937
- setDefault(enabledByDefault:boolean){
1938
- this.data.default = enabledByDefault
1939
- return this
1940
- }
1941
- }
1942
-
1943
-
1944
- /**## ODFileUploadComponentData `type`
1945
- * The configurable settings/options for the `ODFileUploadComponent`.
1946
- */
1947
- export interface ODFileUploadComponentData {
1948
- /**The custom id of this file upload. */
1949
- customId?:string,
1950
- /**Is this file upload required? */
1951
- required:boolean,
1952
- /**The minimum amount of files to upload (0-10). */
1953
- minAmount?:number,
1954
- /**The maximum amount of files to upload (1-10). */
1955
- maxAmount?:number
1956
- }
1957
-
1958
- /**## ODFileUploadComponent `class`
1959
- * A file upload component which allows users to upload one or multiple files inside a modal.
1960
- * The label & description should be set via an `ODLabelComponent`
1961
- */
1962
- export class ODFileUploadComponent extends ODComponent<ODFileUploadComponentData,discord.FileUploadBuilder> {
1963
- constructor(id:ODValidId,data:Partial<ODFileUploadComponentData>){
1964
- const initData: ODFileUploadComponentData = {required:false,...data}
1965
- super(id,"file-upload",initData)
1966
- }
1967
-
1968
- async build(){
1969
- if (typeof this.data.minAmount == "number" && !(this.data.minAmount >= 0 && this.data.minAmount <= 10)) throw new ODSystemError("ODFileUploadComponent:build('"+this.id.value+"') => Minimum upload amount must be a value from 0 to 10.")
1970
- if (typeof this.data.maxAmount == "number" && !(this.data.maxAmount >= 1 && this.data.maxAmount <= 10)) throw new ODSystemError("ODFileUploadComponent:build('"+this.id.value+"') => Maximum upload amount must be a value from 1 to 10.")
1971
-
1972
- return new discord.FileUploadBuilder({
1973
- custom_id:this.data.customId,
1974
- required:this.data.required,
1975
- min_values:this.data.minAmount,
1976
- max_values:this.data.maxAmount
1977
- })
1978
- }
1979
-
1980
- /**Set the custom id of this dropdown. */
1981
- setCustomId(id:string|null){
1982
- this.data.customId = id ?? undefined
1983
- return this
1984
- }
1985
- /**Mark this file upload as required. */
1986
- setRequired(required:boolean){
1987
- this.data.required = required
1988
- return this
1989
- }
1990
- /**Set the minimum amount of files to upload (0-10). */
1991
- setMinAmount(amount:number|null){
1992
- this.data.minAmount = amount ?? undefined
1993
- return this
1994
- }
1995
- /**Set the maximum amount of files to upload (1-10). */
1996
- setMaxAmount(amount:number|null){
1997
- this.data.maxAmount = amount ?? undefined
1998
- return this
1999
- }
2000
- }