@ovencord/builders 1.11.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/LICENSE +191 -0
- package/README.md +92 -0
- package/package.json +70 -0
- package/src/Assertions.ts +15 -0
- package/src/components/ActionRow.ts +346 -0
- package/src/components/Assertions.ts +190 -0
- package/src/components/Component.ts +47 -0
- package/src/components/Components.ts +275 -0
- package/src/components/button/Button.ts +34 -0
- package/src/components/button/CustomIdButton.ts +74 -0
- package/src/components/button/LinkButton.ts +39 -0
- package/src/components/button/PremiumButton.ts +26 -0
- package/src/components/button/mixins/EmojiOrLabelButtonMixin.ts +52 -0
- package/src/components/fileUpload/Assertions.ts +12 -0
- package/src/components/fileUpload/FileUpload.ts +109 -0
- package/src/components/label/Assertions.ts +28 -0
- package/src/components/label/Label.ts +215 -0
- package/src/components/selectMenu/BaseSelectMenu.ts +89 -0
- package/src/components/selectMenu/ChannelSelectMenu.ts +115 -0
- package/src/components/selectMenu/MentionableSelectMenu.ts +126 -0
- package/src/components/selectMenu/RoleSelectMenu.ts +89 -0
- package/src/components/selectMenu/StringSelectMenu.ts +165 -0
- package/src/components/selectMenu/StringSelectMenuOption.ts +113 -0
- package/src/components/selectMenu/UserSelectMenu.ts +89 -0
- package/src/components/textInput/Assertions.ts +15 -0
- package/src/components/textInput/TextInput.ts +154 -0
- package/src/components/v2/Assertions.ts +82 -0
- package/src/components/v2/Container.ts +254 -0
- package/src/components/v2/File.ts +81 -0
- package/src/components/v2/MediaGallery.ts +128 -0
- package/src/components/v2/MediaGalleryItem.ts +85 -0
- package/src/components/v2/Section.ts +266 -0
- package/src/components/v2/Separator.ts +82 -0
- package/src/components/v2/TextDisplay.ts +63 -0
- package/src/components/v2/Thumbnail.ts +100 -0
- package/src/index.ts +109 -0
- package/src/interactions/commands/Command.ts +87 -0
- package/src/interactions/commands/SharedName.ts +68 -0
- package/src/interactions/commands/SharedNameAndDescription.ts +69 -0
- package/src/interactions/commands/chatInput/Assertions.ts +180 -0
- package/src/interactions/commands/chatInput/ChatInputCommand.ts +40 -0
- package/src/interactions/commands/chatInput/ChatInputCommandSubcommands.ts +117 -0
- package/src/interactions/commands/chatInput/mixins/ApplicationCommandNumericOptionMinMaxValueMixin.ts +52 -0
- package/src/interactions/commands/chatInput/mixins/ApplicationCommandOptionChannelTypesMixin.ts +57 -0
- package/src/interactions/commands/chatInput/mixins/ApplicationCommandOptionWithAutocompleteMixin.ts +32 -0
- package/src/interactions/commands/chatInput/mixins/ApplicationCommandOptionWithChoicesMixin.ts +43 -0
- package/src/interactions/commands/chatInput/mixins/SharedChatInputCommandOptions.ts +204 -0
- package/src/interactions/commands/chatInput/mixins/SharedSubcommands.ts +61 -0
- package/src/interactions/commands/chatInput/options/ApplicationCommandOptionBase.ts +66 -0
- package/src/interactions/commands/chatInput/options/attachment.ts +20 -0
- package/src/interactions/commands/chatInput/options/boolean.ts +20 -0
- package/src/interactions/commands/chatInput/options/channel.ts +28 -0
- package/src/interactions/commands/chatInput/options/integer.ts +34 -0
- package/src/interactions/commands/chatInput/options/mentionable.ts +20 -0
- package/src/interactions/commands/chatInput/options/number.ts +34 -0
- package/src/interactions/commands/chatInput/options/role.ts +20 -0
- package/src/interactions/commands/chatInput/options/string.ts +71 -0
- package/src/interactions/commands/chatInput/options/user.ts +20 -0
- package/src/interactions/commands/contextMenu/Assertions.ts +31 -0
- package/src/interactions/commands/contextMenu/ContextMenuCommand.ts +42 -0
- package/src/interactions/commands/contextMenu/MessageCommand.ts +19 -0
- package/src/interactions/commands/contextMenu/UserCommand.ts +19 -0
- package/src/interactions/modals/Assertions.ts +27 -0
- package/src/interactions/modals/Modal.ts +158 -0
- package/src/messages/AllowedMentions.ts +193 -0
- package/src/messages/Assertions.ts +148 -0
- package/src/messages/Attachment.ts +209 -0
- package/src/messages/Message.ts +692 -0
- package/src/messages/MessageReference.ts +111 -0
- package/src/messages/embed/Assertions.ts +53 -0
- package/src/messages/embed/Embed.ts +352 -0
- package/src/messages/embed/EmbedAuthor.ts +83 -0
- package/src/messages/embed/EmbedField.ts +67 -0
- package/src/messages/embed/EmbedFooter.ts +65 -0
- package/src/messages/poll/Assertions.ts +20 -0
- package/src/messages/poll/Poll.ts +243 -0
- package/src/messages/poll/PollAnswer.ts +77 -0
- package/src/messages/poll/PollAnswerMedia.ts +38 -0
- package/src/messages/poll/PollMedia.ts +41 -0
- package/src/messages/poll/PollQuestion.ts +20 -0
- package/src/util/ValidationError.ts +21 -0
- package/src/util/normalizeArray.ts +19 -0
- package/src/util/resolveBuilder.ts +40 -0
- package/src/util/validation.ts +58 -0
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type APIComponentInMessageActionRow,
|
|
3
|
+
type APISeparatorComponent,
|
|
4
|
+
type APIActionRowComponent,
|
|
5
|
+
type APIFileComponent,
|
|
6
|
+
type APITextDisplayComponent,
|
|
7
|
+
type APIContainerComponent,
|
|
8
|
+
type APIComponentInContainer,
|
|
9
|
+
type APIMediaGalleryComponent,
|
|
10
|
+
type APISectionComponent,
|
|
11
|
+
ComponentType,
|
|
12
|
+
} from 'discord-api-types/v10';
|
|
13
|
+
import { normalizeArray, type RestOrArray } from '../../util/normalizeArray';
|
|
14
|
+
import { resolveBuilder } from '../../util/resolveBuilder';
|
|
15
|
+
import { validate } from '../../util/validation';
|
|
16
|
+
import { ActionRowBuilder } from '../ActionRow.js';
|
|
17
|
+
import { ComponentBuilder } from '../Component.js';
|
|
18
|
+
import { createComponentBuilder } from '../Components';
|
|
19
|
+
import { containerPredicate } from './Assertions';
|
|
20
|
+
import { FileBuilder } from './File.js';
|
|
21
|
+
import { MediaGalleryBuilder } from './MediaGallery';
|
|
22
|
+
import { SectionBuilder } from './Section';
|
|
23
|
+
import { SeparatorBuilder } from './Separator.js';
|
|
24
|
+
import { TextDisplayBuilder } from './TextDisplay';
|
|
25
|
+
|
|
26
|
+
export type ContainerComponentBuilders =
|
|
27
|
+
| ActionRowBuilder
|
|
28
|
+
| FileBuilder
|
|
29
|
+
| MediaGalleryBuilder
|
|
30
|
+
| SectionBuilder
|
|
31
|
+
| SeparatorBuilder
|
|
32
|
+
| TextDisplayBuilder;
|
|
33
|
+
|
|
34
|
+
export interface ContainerBuilderData extends Partial<Omit<APIContainerComponent, 'components'>> {
|
|
35
|
+
components: ContainerComponentBuilders[];
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* A builder that creates API-compatible JSON data for containers.
|
|
40
|
+
*/
|
|
41
|
+
export class ContainerBuilder extends ComponentBuilder<APIContainerComponent> {
|
|
42
|
+
/**
|
|
43
|
+
* @internal
|
|
44
|
+
*/
|
|
45
|
+
protected readonly data: ContainerBuilderData;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Gets the components within this container.
|
|
49
|
+
*/
|
|
50
|
+
public get components(): readonly ContainerComponentBuilders[] {
|
|
51
|
+
return this.data.components;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Creates a new container builder.
|
|
56
|
+
*
|
|
57
|
+
* @param data - The API data to create the container with
|
|
58
|
+
*/
|
|
59
|
+
public constructor(data: Partial<APIContainerComponent> = {}) {
|
|
60
|
+
super();
|
|
61
|
+
|
|
62
|
+
const { components = [], ...rest } = data;
|
|
63
|
+
|
|
64
|
+
this.data = {
|
|
65
|
+
...structuredClone(rest),
|
|
66
|
+
components: components.map((component) => createComponentBuilder(component)),
|
|
67
|
+
type: ComponentType.Container,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Sets the accent color of this container.
|
|
73
|
+
*
|
|
74
|
+
* @param color - The color to use
|
|
75
|
+
*/
|
|
76
|
+
public setAccentColor(color: number) {
|
|
77
|
+
this.data.accent_color = color;
|
|
78
|
+
return this;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Clears the accent color of this container.
|
|
83
|
+
*/
|
|
84
|
+
public clearAccentColor() {
|
|
85
|
+
this.data.accent_color = undefined;
|
|
86
|
+
return this;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Sets the spoiler status of this container.
|
|
91
|
+
*
|
|
92
|
+
* @param spoiler - The spoiler status to use
|
|
93
|
+
*/
|
|
94
|
+
public setSpoiler(spoiler = true) {
|
|
95
|
+
this.data.spoiler = spoiler;
|
|
96
|
+
return this;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Adds action row components to this container.
|
|
101
|
+
*
|
|
102
|
+
* @param input - The action row to add
|
|
103
|
+
*/
|
|
104
|
+
public addActionRowComponents(
|
|
105
|
+
...input: RestOrArray<
|
|
106
|
+
| ActionRowBuilder
|
|
107
|
+
| APIActionRowComponent<APIComponentInMessageActionRow>
|
|
108
|
+
| ((builder: ActionRowBuilder) => ActionRowBuilder)
|
|
109
|
+
>
|
|
110
|
+
): this {
|
|
111
|
+
const normalized = normalizeArray(input);
|
|
112
|
+
const resolved = normalized.map((component) => resolveBuilder(component, ActionRowBuilder));
|
|
113
|
+
|
|
114
|
+
this.data.components.push(...resolved);
|
|
115
|
+
return this;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Adds file components to this container.
|
|
120
|
+
*
|
|
121
|
+
* @param input - The file components to add
|
|
122
|
+
*/
|
|
123
|
+
public addFileComponents(
|
|
124
|
+
...input: RestOrArray<APIFileComponent | FileBuilder | ((builder: FileBuilder) => FileBuilder)>
|
|
125
|
+
): this {
|
|
126
|
+
const normalized = normalizeArray(input);
|
|
127
|
+
const resolved = normalized.map((component) => resolveBuilder(component, FileBuilder));
|
|
128
|
+
|
|
129
|
+
this.data.components.push(...resolved);
|
|
130
|
+
return this;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Adds media gallery components to this container.
|
|
135
|
+
*
|
|
136
|
+
* @param input - The media gallery components to add
|
|
137
|
+
*/
|
|
138
|
+
public addMediaGalleryComponents(
|
|
139
|
+
...input: RestOrArray<
|
|
140
|
+
APIMediaGalleryComponent | MediaGalleryBuilder | ((builder: MediaGalleryBuilder) => MediaGalleryBuilder)
|
|
141
|
+
>
|
|
142
|
+
): this {
|
|
143
|
+
const normalized = normalizeArray(input);
|
|
144
|
+
const resolved = normalized.map((component) => resolveBuilder(component, MediaGalleryBuilder));
|
|
145
|
+
|
|
146
|
+
this.data.components.push(...resolved);
|
|
147
|
+
return this;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Adds section components to this container.
|
|
152
|
+
*
|
|
153
|
+
* @param input - The section components to add
|
|
154
|
+
*/
|
|
155
|
+
public addSectionComponents(
|
|
156
|
+
...input: RestOrArray<APISectionComponent | SectionBuilder | ((builder: SectionBuilder) => SectionBuilder)>
|
|
157
|
+
): this {
|
|
158
|
+
const normalized = normalizeArray(input);
|
|
159
|
+
const resolved = normalized.map((component) => resolveBuilder(component, SectionBuilder));
|
|
160
|
+
|
|
161
|
+
this.data.components.push(...resolved);
|
|
162
|
+
return this;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Adds separator components to this container.
|
|
167
|
+
*
|
|
168
|
+
* @param input - The separator components to add
|
|
169
|
+
*/
|
|
170
|
+
public addSeparatorComponents(
|
|
171
|
+
...input: RestOrArray<APISeparatorComponent | SeparatorBuilder | ((builder: SeparatorBuilder) => SeparatorBuilder)>
|
|
172
|
+
): this {
|
|
173
|
+
const normalized = normalizeArray(input);
|
|
174
|
+
const resolved = normalized.map((component) => resolveBuilder(component, SeparatorBuilder));
|
|
175
|
+
|
|
176
|
+
this.data.components.push(...resolved);
|
|
177
|
+
return this;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Adds text display components to this container.
|
|
182
|
+
*
|
|
183
|
+
* @param input - The text display components to add
|
|
184
|
+
*/
|
|
185
|
+
public addTextDisplayComponents(
|
|
186
|
+
...input: RestOrArray<
|
|
187
|
+
APITextDisplayComponent | TextDisplayBuilder | ((builder: TextDisplayBuilder) => TextDisplayBuilder)
|
|
188
|
+
>
|
|
189
|
+
): this {
|
|
190
|
+
const normalized = normalizeArray(input);
|
|
191
|
+
const resolved = normalized.map((component) => resolveBuilder(component, TextDisplayBuilder));
|
|
192
|
+
|
|
193
|
+
this.data.components.push(...resolved);
|
|
194
|
+
return this;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Removes, replaces, or inserts components for this container
|
|
199
|
+
*
|
|
200
|
+
* @remarks
|
|
201
|
+
* This method behaves similarly
|
|
202
|
+
* to {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/splice | Array.prototype.splice()}.
|
|
203
|
+
*
|
|
204
|
+
* It's useful for modifying and adjusting order of the already-existing components of a container.
|
|
205
|
+
* @example
|
|
206
|
+
* Remove the first component:
|
|
207
|
+
* ```ts
|
|
208
|
+
* container.spliceComponents(0, 1);
|
|
209
|
+
* ```
|
|
210
|
+
* @example
|
|
211
|
+
* Remove the first n components:
|
|
212
|
+
* ```ts
|
|
213
|
+
* const n = 4;
|
|
214
|
+
* container.spliceComponents(0, n);
|
|
215
|
+
* ```
|
|
216
|
+
* @example
|
|
217
|
+
* Remove the last component:
|
|
218
|
+
* ```ts
|
|
219
|
+
* container.spliceComponents(-1, 1);
|
|
220
|
+
* ```
|
|
221
|
+
* @param index - The index to start at
|
|
222
|
+
* @param deleteCount - The number of components to remove
|
|
223
|
+
* @param components - The replacing component objects
|
|
224
|
+
*/
|
|
225
|
+
public spliceComponents(
|
|
226
|
+
index: number,
|
|
227
|
+
deleteCount: number,
|
|
228
|
+
...components: RestOrArray<APIComponentInContainer | ContainerComponentBuilders>
|
|
229
|
+
): this {
|
|
230
|
+
const normalized = normalizeArray(components);
|
|
231
|
+
const resolved = normalized.map((component) =>
|
|
232
|
+
component instanceof ComponentBuilder ? component : createComponentBuilder(component),
|
|
233
|
+
);
|
|
234
|
+
|
|
235
|
+
this.data.components.splice(index, deleteCount, ...resolved);
|
|
236
|
+
return this;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* {@inheritDoc ComponentBuilder.toJSON}
|
|
241
|
+
*/
|
|
242
|
+
public override toJSON(validationOverride?: boolean): APIContainerComponent {
|
|
243
|
+
const { components, ...rest } = this.data;
|
|
244
|
+
|
|
245
|
+
const data = {
|
|
246
|
+
...structuredClone(rest),
|
|
247
|
+
components: components.map((component) => component.toJSON(false)),
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
validate(containerPredicate, data, validationOverride);
|
|
251
|
+
|
|
252
|
+
return data as APIContainerComponent;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { ComponentType, type APIFileComponent } from 'discord-api-types/v10';
|
|
2
|
+
import { validate } from '../../util/validation.js';
|
|
3
|
+
import { ComponentBuilder } from '../Component.js';
|
|
4
|
+
import { filePredicate } from './Assertions.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* A builder that creates API-compatible JSON data for files.
|
|
8
|
+
*/
|
|
9
|
+
export class FileBuilder extends ComponentBuilder<APIFileComponent> {
|
|
10
|
+
/**
|
|
11
|
+
* @internal
|
|
12
|
+
*/
|
|
13
|
+
protected readonly data: Partial<APIFileComponent>;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Creates a new file.
|
|
17
|
+
*
|
|
18
|
+
* @param data - The API data to create this file with
|
|
19
|
+
* @example
|
|
20
|
+
* Creating a file from an API data object:
|
|
21
|
+
* ```ts
|
|
22
|
+
* const file = new FileBuilder({
|
|
23
|
+
* spoiler: true,
|
|
24
|
+
* file: {
|
|
25
|
+
* url: 'attachment://file.png',
|
|
26
|
+
* },
|
|
27
|
+
* });
|
|
28
|
+
* ```
|
|
29
|
+
* @example
|
|
30
|
+
* Creating a file using setters and API data:
|
|
31
|
+
* ```ts
|
|
32
|
+
* const file = new FileBuilder({
|
|
33
|
+
* file: {
|
|
34
|
+
* url: 'attachment://image.jpg',
|
|
35
|
+
* },
|
|
36
|
+
* })
|
|
37
|
+
* .setSpoiler(false);
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
public constructor(data: Partial<APIFileComponent> = {}) {
|
|
41
|
+
super();
|
|
42
|
+
|
|
43
|
+
const { file, ...rest } = data;
|
|
44
|
+
|
|
45
|
+
this.data = {
|
|
46
|
+
...structuredClone(rest),
|
|
47
|
+
file: file && { url: file.url },
|
|
48
|
+
type: ComponentType.File,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Sets the spoiler status of this file.
|
|
54
|
+
*
|
|
55
|
+
* @param spoiler - The spoiler status to use
|
|
56
|
+
*/
|
|
57
|
+
public setSpoiler(spoiler = true) {
|
|
58
|
+
this.data.spoiler = spoiler;
|
|
59
|
+
return this;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Sets the media URL of this file.
|
|
64
|
+
*
|
|
65
|
+
* @param url - The URL to use
|
|
66
|
+
*/
|
|
67
|
+
public setURL(url: string) {
|
|
68
|
+
this.data.file = { url };
|
|
69
|
+
return this;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* {@inheritDoc ComponentBuilder.toJSON}
|
|
74
|
+
*/
|
|
75
|
+
public override toJSON(validationOverride?: boolean): APIFileComponent {
|
|
76
|
+
const clone = structuredClone(this.data);
|
|
77
|
+
validate(filePredicate, clone, validationOverride);
|
|
78
|
+
|
|
79
|
+
return clone as APIFileComponent;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { type APIMediaGalleryItem, type APIMediaGalleryComponent, ComponentType } from 'discord-api-types/v10';
|
|
2
|
+
import { normalizeArray, type RestOrArray } from '../../util/normalizeArray.js';
|
|
3
|
+
import { resolveBuilder } from '../../util/resolveBuilder.js';
|
|
4
|
+
import { validate } from '../../util/validation.js';
|
|
5
|
+
import { ComponentBuilder } from '../Component.js';
|
|
6
|
+
import { mediaGalleryPredicate } from './Assertions.js';
|
|
7
|
+
import { MediaGalleryItemBuilder } from './MediaGalleryItem.js';
|
|
8
|
+
|
|
9
|
+
export interface MediaGalleryBuilderData extends Partial<Omit<APIMediaGalleryComponent, 'items'>> {
|
|
10
|
+
items: MediaGalleryItemBuilder[];
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* A builder that creates API-compatible JSON data for media galleries.
|
|
15
|
+
*/
|
|
16
|
+
export class MediaGalleryBuilder extends ComponentBuilder<APIMediaGalleryComponent> {
|
|
17
|
+
/**
|
|
18
|
+
* @internal
|
|
19
|
+
*/
|
|
20
|
+
protected readonly data: MediaGalleryBuilderData;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* The items in this media gallery.
|
|
24
|
+
*/
|
|
25
|
+
public get items(): readonly MediaGalleryItemBuilder[] {
|
|
26
|
+
return this.data.items;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Creates a new media gallery.
|
|
31
|
+
*
|
|
32
|
+
* @param data - The API data to create this container with
|
|
33
|
+
* @example
|
|
34
|
+
* Creating a media gallery from an API data object:
|
|
35
|
+
* ```ts
|
|
36
|
+
* const mediaGallery = new MediaGalleryBuilder({
|
|
37
|
+
* items: [
|
|
38
|
+
* {
|
|
39
|
+
* description: "Some text here",
|
|
40
|
+
* media: {
|
|
41
|
+
* url: 'https://cdn.discordapp.com/embed/avatars/2.png',
|
|
42
|
+
* },
|
|
43
|
+
* },
|
|
44
|
+
* ],
|
|
45
|
+
* });
|
|
46
|
+
* ```
|
|
47
|
+
* @example
|
|
48
|
+
* Creating a media gallery using setters and API data:
|
|
49
|
+
* ```ts
|
|
50
|
+
* const mediaGallery = new MediaGalleryBuilder({
|
|
51
|
+
* items: [
|
|
52
|
+
* {
|
|
53
|
+
* description: "alt text",
|
|
54
|
+
* media: {
|
|
55
|
+
* url: 'https://cdn.discordapp.com/embed/avatars/5.png',
|
|
56
|
+
* },
|
|
57
|
+
* },
|
|
58
|
+
* ],
|
|
59
|
+
* })
|
|
60
|
+
* .addItems(item2, item3);
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
public constructor(data: Partial<APIMediaGalleryComponent> = {}) {
|
|
64
|
+
super();
|
|
65
|
+
|
|
66
|
+
const { items = [], ...rest } = data;
|
|
67
|
+
|
|
68
|
+
this.data = {
|
|
69
|
+
...structuredClone(rest),
|
|
70
|
+
items: items.map((item) => new MediaGalleryItemBuilder(item)),
|
|
71
|
+
type: ComponentType.MediaGallery,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Adds a media gallery item to this media gallery.
|
|
77
|
+
*
|
|
78
|
+
* @param input - The items to add
|
|
79
|
+
*/
|
|
80
|
+
public addItems(
|
|
81
|
+
...input: RestOrArray<
|
|
82
|
+
APIMediaGalleryItem | MediaGalleryItemBuilder | ((builder: MediaGalleryItemBuilder) => MediaGalleryItemBuilder)
|
|
83
|
+
>
|
|
84
|
+
): this {
|
|
85
|
+
const normalized = normalizeArray(input);
|
|
86
|
+
const resolved = normalized.map((item) => resolveBuilder(item, MediaGalleryItemBuilder));
|
|
87
|
+
|
|
88
|
+
this.data.items.push(...resolved);
|
|
89
|
+
return this;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Removes, replaces, or inserts media gallery items for this media gallery.
|
|
94
|
+
*
|
|
95
|
+
* @param index - The index to start removing, replacing or inserting items
|
|
96
|
+
* @param deleteCount - The amount of items to remove
|
|
97
|
+
* @param items - The items to insert
|
|
98
|
+
*/
|
|
99
|
+
public spliceItems(
|
|
100
|
+
index: number,
|
|
101
|
+
deleteCount: number,
|
|
102
|
+
...items: RestOrArray<
|
|
103
|
+
APIMediaGalleryItem | MediaGalleryItemBuilder | ((builder: MediaGalleryItemBuilder) => MediaGalleryItemBuilder)
|
|
104
|
+
>
|
|
105
|
+
) {
|
|
106
|
+
const normalized = normalizeArray(items);
|
|
107
|
+
const resolved = normalized.map((item) => resolveBuilder(item, MediaGalleryItemBuilder));
|
|
108
|
+
|
|
109
|
+
this.data.items.splice(index, deleteCount, ...resolved);
|
|
110
|
+
return this;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* {@inheritDoc ComponentBuilder.toJSON}
|
|
115
|
+
*/
|
|
116
|
+
public override toJSON(validationOverride?: boolean): APIMediaGalleryComponent {
|
|
117
|
+
const { items, ...rest } = this.data;
|
|
118
|
+
|
|
119
|
+
const data = {
|
|
120
|
+
...structuredClone(rest),
|
|
121
|
+
items: items.map((item) => item.toJSON(false)),
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
validate(mediaGalleryPredicate, data, validationOverride);
|
|
125
|
+
|
|
126
|
+
return data as APIMediaGalleryComponent;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import type { JSONEncodable } from '@ovencord/util';
|
|
2
|
+
import type { APIMediaGalleryItem } from 'discord-api-types/v10';
|
|
3
|
+
import { validate } from '../../util/validation.js';
|
|
4
|
+
import { mediaGalleryItemPredicate } from './Assertions.js';
|
|
5
|
+
|
|
6
|
+
export class MediaGalleryItemBuilder implements JSONEncodable<APIMediaGalleryItem> {
|
|
7
|
+
private readonly data: Partial<APIMediaGalleryItem>;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Creates a new media gallery item.
|
|
11
|
+
*
|
|
12
|
+
* @param data - The API data to create this media gallery item with
|
|
13
|
+
* @example
|
|
14
|
+
* Creating a media gallery item from an API data object:
|
|
15
|
+
* ```ts
|
|
16
|
+
* const item = new MediaGalleryItemBuilder({
|
|
17
|
+
* description: "Some text here",
|
|
18
|
+
* media: {
|
|
19
|
+
* url: 'https://cdn.discordapp.com/embed/avatars/2.png',
|
|
20
|
+
* },
|
|
21
|
+
* });
|
|
22
|
+
* ```
|
|
23
|
+
* @example
|
|
24
|
+
* Creating a media gallery item using setters and API data:
|
|
25
|
+
* ```ts
|
|
26
|
+
* const item = new MediaGalleryItemBuilder({
|
|
27
|
+
* media: {
|
|
28
|
+
* url: 'https://cdn.discordapp.com/embed/avatars/5.png',
|
|
29
|
+
* },
|
|
30
|
+
* })
|
|
31
|
+
* .setDescription("alt text");
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
public constructor(data: Partial<APIMediaGalleryItem> = {}) {
|
|
35
|
+
this.data = structuredClone(data);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Sets the source URL of this media gallery item.
|
|
40
|
+
*
|
|
41
|
+
* @param url - The URL to use
|
|
42
|
+
*/
|
|
43
|
+
public setURL(url: string) {
|
|
44
|
+
this.data.media = { url };
|
|
45
|
+
return this;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Sets the description of this thumbnail.
|
|
50
|
+
*
|
|
51
|
+
* @param description - The description to use
|
|
52
|
+
*/
|
|
53
|
+
public setDescription(description: string) {
|
|
54
|
+
this.data.description = description;
|
|
55
|
+
return this;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Clears the description of this thumbnail.
|
|
60
|
+
*/
|
|
61
|
+
public clearDescription() {
|
|
62
|
+
this.data.description = undefined;
|
|
63
|
+
return this;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Sets the spoiler status of this thumbnail.
|
|
68
|
+
*
|
|
69
|
+
* @param spoiler - The spoiler status to use
|
|
70
|
+
*/
|
|
71
|
+
public setSpoiler(spoiler = true) {
|
|
72
|
+
this.data.spoiler = spoiler;
|
|
73
|
+
return this;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Transforms this object to its JSON format
|
|
78
|
+
*/
|
|
79
|
+
public toJSON(validationOverride?: boolean): APIMediaGalleryItem {
|
|
80
|
+
const clone = structuredClone(this.data);
|
|
81
|
+
validate(mediaGalleryItemPredicate, clone, validationOverride);
|
|
82
|
+
|
|
83
|
+
return clone as APIMediaGalleryItem;
|
|
84
|
+
}
|
|
85
|
+
}
|