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