district.js 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +28 -0
- package/dist/components.d.ts +64 -3
- package/dist/components.js +48 -4
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/structures.d.ts +20 -6
- package/dist/structures.js +18 -6
- package/dist/types.d.ts +5 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -110,6 +110,34 @@ client.on("interactionCreate", (i) => {
|
|
|
110
110
|
});
|
|
111
111
|
```
|
|
112
112
|
|
|
113
|
+
## Select menus & modals
|
|
114
|
+
|
|
115
|
+
```js
|
|
116
|
+
import { ActionRowBuilder, StringSelectMenuBuilder, ButtonBuilder, ModalBuilder, TextInputBuilder } from "district.js";
|
|
117
|
+
|
|
118
|
+
// Dropdown
|
|
119
|
+
const menu = new ActionRowBuilder().addComponents(
|
|
120
|
+
new StringSelectMenuBuilder().setCustomId("role").setPlaceholder("Pick a role")
|
|
121
|
+
.addOptions({ label: "Dev", value: "dev" }, { label: "Design", value: "design" }),
|
|
122
|
+
);
|
|
123
|
+
await channel.send({ content: "Choose:", components: [menu] });
|
|
124
|
+
|
|
125
|
+
// Modal (opens instantly on click; only the submit is delivered to the bot)
|
|
126
|
+
const modal = new ModalBuilder().setCustomId("feedback").setTitle("Feedback")
|
|
127
|
+
.addComponents(new TextInputBuilder().setCustomId("msg").setLabel("Your message").setStyle("paragraph"));
|
|
128
|
+
const row = new ActionRowBuilder().addComponents(
|
|
129
|
+
new ButtonBuilder().setLabel("Give feedback").setStyle("primary").setModal(modal),
|
|
130
|
+
);
|
|
131
|
+
await channel.send({ components: [row] });
|
|
132
|
+
|
|
133
|
+
client.on("interactionCreate", (i) => {
|
|
134
|
+
if (i.isSelectMenu() && i.customId === "role") i.reply(`You picked ${i.values[0]}`);
|
|
135
|
+
if (i.isModalSubmit() && i.customId === "feedback") i.reply(`Thanks: ${i.field("msg")}`);
|
|
136
|
+
});
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
> Because District delivers interactions asynchronously, modals are attached to a button and shown **instantly, client-side**; only the submitted values are sent back to your bot.
|
|
140
|
+
|
|
113
141
|
## Slash commands
|
|
114
142
|
|
|
115
143
|
Register the command in the portal (name + handler URL), then:
|
package/dist/components.d.ts
CHANGED
|
@@ -1,4 +1,17 @@
|
|
|
1
1
|
export type ButtonStyle = "primary" | "secondary" | "success" | "danger" | "link";
|
|
2
|
+
export interface TextInputData {
|
|
3
|
+
custom_id: string;
|
|
4
|
+
label: string;
|
|
5
|
+
style: "short" | "paragraph";
|
|
6
|
+
placeholder?: string;
|
|
7
|
+
required?: boolean;
|
|
8
|
+
max_length?: number;
|
|
9
|
+
}
|
|
10
|
+
export interface ModalData {
|
|
11
|
+
custom_id: string;
|
|
12
|
+
title: string;
|
|
13
|
+
fields: TextInputData[];
|
|
14
|
+
}
|
|
2
15
|
export interface ButtonData {
|
|
3
16
|
type: "button";
|
|
4
17
|
style: ButtonStyle;
|
|
@@ -7,10 +20,27 @@ export interface ButtonData {
|
|
|
7
20
|
url?: string;
|
|
8
21
|
emoji?: string;
|
|
9
22
|
disabled?: boolean;
|
|
23
|
+
/** A modal shown (instantly, client-side) when the button is clicked. */
|
|
24
|
+
modal?: ModalData;
|
|
25
|
+
}
|
|
26
|
+
export interface SelectOption {
|
|
27
|
+
label: string;
|
|
28
|
+
value: string;
|
|
29
|
+
description?: string;
|
|
30
|
+
}
|
|
31
|
+
export interface SelectData {
|
|
32
|
+
type: "select";
|
|
33
|
+
custom_id: string;
|
|
34
|
+
options: SelectOption[];
|
|
35
|
+
placeholder?: string;
|
|
36
|
+
min_values?: number;
|
|
37
|
+
max_values?: number;
|
|
38
|
+
disabled?: boolean;
|
|
10
39
|
}
|
|
40
|
+
export type ComponentData = ButtonData | SelectData;
|
|
11
41
|
export interface ActionRowData {
|
|
12
42
|
type: "action_row";
|
|
13
|
-
components:
|
|
43
|
+
components: ComponentData[];
|
|
14
44
|
}
|
|
15
45
|
export declare class ButtonBuilder {
|
|
16
46
|
data: Partial<ButtonData>;
|
|
@@ -22,12 +52,43 @@ export declare class ButtonBuilder {
|
|
|
22
52
|
setUrl(url: string): this;
|
|
23
53
|
setEmoji(emoji: string): this;
|
|
24
54
|
setDisabled(disabled?: boolean): this;
|
|
55
|
+
/** Attach a modal — clicking the button opens it instantly; submit fires a
|
|
56
|
+
* modal_submit interaction with the field values. */
|
|
57
|
+
setModal(modal: ModalBuilder | ModalData): this;
|
|
25
58
|
toJSON(): ButtonData;
|
|
26
59
|
}
|
|
60
|
+
export declare class StringSelectMenuBuilder {
|
|
61
|
+
data: SelectData;
|
|
62
|
+
setCustomId(id: string): this;
|
|
63
|
+
setPlaceholder(text: string): this;
|
|
64
|
+
setMinValues(n: number): this;
|
|
65
|
+
setMaxValues(n: number): this;
|
|
66
|
+
setDisabled(disabled?: boolean): this;
|
|
67
|
+
addOptions(...options: SelectOption[]): this;
|
|
68
|
+
toJSON(): SelectData;
|
|
69
|
+
}
|
|
70
|
+
export declare class TextInputBuilder {
|
|
71
|
+
data: Partial<TextInputData>;
|
|
72
|
+
setCustomId(id: string): this;
|
|
73
|
+
setLabel(label: string): this;
|
|
74
|
+
setStyle(style: "short" | "paragraph"): this;
|
|
75
|
+
setPlaceholder(text: string): this;
|
|
76
|
+
setRequired(required?: boolean): this;
|
|
77
|
+
setMaxLength(n: number): this;
|
|
78
|
+
toJSON(): TextInputData;
|
|
79
|
+
}
|
|
80
|
+
export declare class ModalBuilder {
|
|
81
|
+
data: ModalData;
|
|
82
|
+
setCustomId(id: string): this;
|
|
83
|
+
setTitle(title: string): this;
|
|
84
|
+
/** Add text inputs to the modal (up to 5). */
|
|
85
|
+
addComponents(...inputs: (TextInputBuilder | TextInputData)[]): this;
|
|
86
|
+
toJSON(): ModalData;
|
|
87
|
+
}
|
|
27
88
|
export declare class ActionRowBuilder {
|
|
28
89
|
data: ActionRowData;
|
|
29
|
-
/** Add up to 5 buttons
|
|
30
|
-
addComponents(...
|
|
90
|
+
/** Add up to 5 buttons, or a single select menu. */
|
|
91
|
+
addComponents(...components: (ButtonBuilder | StringSelectMenuBuilder | ComponentData)[]): this;
|
|
31
92
|
toJSON(): ActionRowData;
|
|
32
93
|
}
|
|
33
94
|
export type ComponentResolvable = ActionRowBuilder | ActionRowData;
|
package/dist/components.js
CHANGED
|
@@ -12,14 +12,58 @@ export class ButtonBuilder {
|
|
|
12
12
|
setUrl(url) { this.data.url = url; this.data.style = "link"; return this; }
|
|
13
13
|
setEmoji(emoji) { this.data.emoji = emoji; return this; }
|
|
14
14
|
setDisabled(disabled = true) { this.data.disabled = disabled; return this; }
|
|
15
|
+
/** Attach a modal — clicking the button opens it instantly; submit fires a
|
|
16
|
+
* modal_submit interaction with the field values. */
|
|
17
|
+
setModal(modal) {
|
|
18
|
+
this.data.modal = modal instanceof ModalBuilder ? modal.toJSON() : modal;
|
|
19
|
+
if (!this.data.custom_id)
|
|
20
|
+
this.data.custom_id = this.data.modal.custom_id;
|
|
21
|
+
return this;
|
|
22
|
+
}
|
|
23
|
+
toJSON() { return this.data; }
|
|
24
|
+
}
|
|
25
|
+
export class StringSelectMenuBuilder {
|
|
26
|
+
data = { type: "select", custom_id: "", options: [] };
|
|
27
|
+
setCustomId(id) { this.data.custom_id = id; return this; }
|
|
28
|
+
setPlaceholder(text) { this.data.placeholder = text; return this; }
|
|
29
|
+
setMinValues(n) { this.data.min_values = n; return this; }
|
|
30
|
+
setMaxValues(n) { this.data.max_values = n; return this; }
|
|
31
|
+
setDisabled(disabled = true) { this.data.disabled = disabled; return this; }
|
|
32
|
+
addOptions(...options) {
|
|
33
|
+
this.data.options.push(...options);
|
|
34
|
+
return this;
|
|
35
|
+
}
|
|
36
|
+
toJSON() { return this.data; }
|
|
37
|
+
}
|
|
38
|
+
export class TextInputBuilder {
|
|
39
|
+
data = { style: "short", required: true };
|
|
40
|
+
setCustomId(id) { this.data.custom_id = id; return this; }
|
|
41
|
+
setLabel(label) { this.data.label = label; return this; }
|
|
42
|
+
setStyle(style) { this.data.style = style; return this; }
|
|
43
|
+
setPlaceholder(text) { this.data.placeholder = text; return this; }
|
|
44
|
+
setRequired(required = true) { this.data.required = required; return this; }
|
|
45
|
+
setMaxLength(n) { this.data.max_length = n; return this; }
|
|
46
|
+
toJSON() { return this.data; }
|
|
47
|
+
}
|
|
48
|
+
export class ModalBuilder {
|
|
49
|
+
data = { custom_id: "", title: "", fields: [] };
|
|
50
|
+
setCustomId(id) { this.data.custom_id = id; return this; }
|
|
51
|
+
setTitle(title) { this.data.title = title; return this; }
|
|
52
|
+
/** Add text inputs to the modal (up to 5). */
|
|
53
|
+
addComponents(...inputs) {
|
|
54
|
+
for (const i of inputs)
|
|
55
|
+
this.data.fields.push(i instanceof TextInputBuilder ? i.toJSON() : i);
|
|
56
|
+
return this;
|
|
57
|
+
}
|
|
15
58
|
toJSON() { return this.data; }
|
|
16
59
|
}
|
|
17
60
|
export class ActionRowBuilder {
|
|
18
61
|
data = { type: "action_row", components: [] };
|
|
19
|
-
/** Add up to 5 buttons
|
|
20
|
-
addComponents(...
|
|
21
|
-
for (const
|
|
22
|
-
this.data.components.push(
|
|
62
|
+
/** Add up to 5 buttons, or a single select menu. */
|
|
63
|
+
addComponents(...components) {
|
|
64
|
+
for (const c of components) {
|
|
65
|
+
this.data.components.push(c instanceof ButtonBuilder || c instanceof StringSelectMenuBuilder ? c.toJSON() : c);
|
|
66
|
+
}
|
|
23
67
|
return this;
|
|
24
68
|
}
|
|
25
69
|
toJSON() { return this.data; }
|
package/dist/index.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ export { Client, type ClientEvents } from "./client.js";
|
|
|
2
2
|
export { REST, DistrictAPIError, DEFAULT_API_BASE } from "./rest.js";
|
|
3
3
|
export { ClientUser, Message, TextChannel, Interaction, User, Space, SpaceMember, Role, Attachment, Ban, Invite, Webhook, type ClientContext, type MessageContent, } from "./structures.js";
|
|
4
4
|
export { EmbedBuilder, resolveEmbed, type EmbedData, type EmbedField, type EmbedResolvable } from "./embed.js";
|
|
5
|
-
export { ButtonBuilder, ActionRowBuilder, resolveComponent, type ButtonStyle, type ButtonData, type ActionRowData, type ComponentResolvable, } from "./components.js";
|
|
5
|
+
export { ButtonBuilder, ActionRowBuilder, StringSelectMenuBuilder, ModalBuilder, TextInputBuilder, resolveComponent, type ButtonStyle, type ButtonData, type SelectData, type SelectOption, type ComponentData, type ModalData, type TextInputData, type ActionRowData, type ComponentResolvable, } from "./components.js";
|
|
6
6
|
export { Collection } from "./collection.js";
|
|
7
7
|
export { PermissionsBitField, type PermissionResolvable, type PermissionFlagName } from "./permissions.js";
|
|
8
8
|
export { Formatters } from "./formatters.js";
|
package/dist/index.js
CHANGED
|
@@ -8,7 +8,7 @@ export { Client } from "./client.js";
|
|
|
8
8
|
export { REST, DistrictAPIError, DEFAULT_API_BASE } from "./rest.js";
|
|
9
9
|
export { ClientUser, Message, TextChannel, Interaction, User, Space, SpaceMember, Role, Attachment, Ban, Invite, Webhook, } from "./structures.js";
|
|
10
10
|
export { EmbedBuilder, resolveEmbed } from "./embed.js";
|
|
11
|
-
export { ButtonBuilder, ActionRowBuilder, resolveComponent, } from "./components.js";
|
|
11
|
+
export { ButtonBuilder, ActionRowBuilder, StringSelectMenuBuilder, ModalBuilder, TextInputBuilder, resolveComponent, } from "./components.js";
|
|
12
12
|
export { Collection } from "./collection.js";
|
|
13
13
|
export { PermissionsBitField } from "./permissions.js";
|
|
14
14
|
export { Formatters } from "./formatters.js";
|
package/dist/structures.d.ts
CHANGED
|
@@ -205,14 +205,18 @@ export declare class Role {
|
|
|
205
205
|
}
|
|
206
206
|
export declare class Interaction {
|
|
207
207
|
private client;
|
|
208
|
-
/** "command" (slash
|
|
209
|
-
type: "command" | "component";
|
|
208
|
+
/** "command" (slash), "component" (button/select), or "modal_submit". */
|
|
209
|
+
type: "command" | "component" | "modal_submit";
|
|
210
210
|
commandName: string;
|
|
211
211
|
commandId: string;
|
|
212
|
-
/** The
|
|
212
|
+
/** The component/modal customId that triggered this. */
|
|
213
213
|
customId: string;
|
|
214
|
-
/** The message the component is on
|
|
214
|
+
/** The message the component is on. */
|
|
215
215
|
messageId: string | null;
|
|
216
|
+
/** Selected values (select-menu interactions). */
|
|
217
|
+
values: string[];
|
|
218
|
+
/** Submitted field values keyed by input customId (modal submits). */
|
|
219
|
+
fields: Record<string, string>;
|
|
216
220
|
spaceId: string;
|
|
217
221
|
channelId: string;
|
|
218
222
|
userId: string;
|
|
@@ -227,11 +231,21 @@ export declare class Interaction {
|
|
|
227
231
|
channel_id: string;
|
|
228
232
|
user_id: string;
|
|
229
233
|
args?: Record<string, unknown>;
|
|
234
|
+
data?: {
|
|
235
|
+
values?: string[];
|
|
236
|
+
fields?: Record<string, string>;
|
|
237
|
+
};
|
|
230
238
|
});
|
|
231
|
-
/** True if this is a button click. */
|
|
232
|
-
isButton(): boolean;
|
|
233
239
|
/** True if this is a slash command. */
|
|
234
240
|
isCommand(): boolean;
|
|
241
|
+
/** True if this is a button click (component with no selected values). */
|
|
242
|
+
isButton(): boolean;
|
|
243
|
+
/** True if this is a select-menu choice. */
|
|
244
|
+
isSelectMenu(): boolean;
|
|
245
|
+
/** True if this is a submitted modal. */
|
|
246
|
+
isModalSubmit(): boolean;
|
|
247
|
+
/** Get a submitted modal field value by its input customId. */
|
|
248
|
+
field(customId: string): string | undefined;
|
|
235
249
|
/** Respond to the command by posting a message in its channel. */
|
|
236
250
|
reply(content: MessageContent): Promise<Message>;
|
|
237
251
|
}
|
package/dist/structures.js
CHANGED
|
@@ -376,34 +376,46 @@ export class Role {
|
|
|
376
376
|
}
|
|
377
377
|
export class Interaction {
|
|
378
378
|
client;
|
|
379
|
-
/** "command" (slash
|
|
379
|
+
/** "command" (slash), "component" (button/select), or "modal_submit". */
|
|
380
380
|
type;
|
|
381
381
|
commandName;
|
|
382
382
|
commandId;
|
|
383
|
-
/** The
|
|
383
|
+
/** The component/modal customId that triggered this. */
|
|
384
384
|
customId;
|
|
385
|
-
/** The message the component is on
|
|
385
|
+
/** The message the component is on. */
|
|
386
386
|
messageId;
|
|
387
|
+
/** Selected values (select-menu interactions). */
|
|
388
|
+
values;
|
|
389
|
+
/** Submitted field values keyed by input customId (modal submits). */
|
|
390
|
+
fields;
|
|
387
391
|
spaceId;
|
|
388
392
|
channelId;
|
|
389
393
|
userId;
|
|
390
394
|
args;
|
|
391
395
|
constructor(client, raw) {
|
|
392
396
|
this.client = client;
|
|
393
|
-
this.type = raw.type === "component" ? "component" : "command";
|
|
397
|
+
this.type = raw.type === "component" ? "component" : raw.type === "modal_submit" ? "modal_submit" : "command";
|
|
394
398
|
this.commandName = raw.command ?? "";
|
|
395
399
|
this.commandId = raw.command_id ?? "";
|
|
396
400
|
this.customId = raw.custom_id ?? "";
|
|
397
401
|
this.messageId = raw.message_id ?? null;
|
|
402
|
+
this.values = Array.isArray(raw.data?.values) ? raw.data.values : [];
|
|
403
|
+
this.fields = raw.data?.fields && typeof raw.data.fields === "object" ? raw.data.fields : {};
|
|
398
404
|
this.spaceId = raw.space_id;
|
|
399
405
|
this.channelId = raw.channel_id;
|
|
400
406
|
this.userId = raw.user_id;
|
|
401
407
|
this.args = raw.args ?? {};
|
|
402
408
|
}
|
|
403
|
-
/** True if this is a button click. */
|
|
404
|
-
isButton() { return this.type === "component"; }
|
|
405
409
|
/** True if this is a slash command. */
|
|
406
410
|
isCommand() { return this.type === "command"; }
|
|
411
|
+
/** True if this is a button click (component with no selected values). */
|
|
412
|
+
isButton() { return this.type === "component" && this.values.length === 0; }
|
|
413
|
+
/** True if this is a select-menu choice. */
|
|
414
|
+
isSelectMenu() { return this.type === "component" && this.values.length > 0; }
|
|
415
|
+
/** True if this is a submitted modal. */
|
|
416
|
+
isModalSubmit() { return this.type === "modal_submit"; }
|
|
417
|
+
/** Get a submitted modal field value by its input customId. */
|
|
418
|
+
field(customId) { return this.fields[customId]; }
|
|
407
419
|
/** Respond to the command by posting a message in its channel. */
|
|
408
420
|
async reply(content) {
|
|
409
421
|
const p = toPayload(content);
|
package/dist/types.d.ts
CHANGED
|
@@ -146,7 +146,7 @@ export type DistrictEvent = {
|
|
|
146
146
|
emoji: string;
|
|
147
147
|
} | {
|
|
148
148
|
event: "interaction.create";
|
|
149
|
-
type?: "command" | "component";
|
|
149
|
+
type?: "command" | "component" | "modal_submit";
|
|
150
150
|
command?: string;
|
|
151
151
|
command_id?: string;
|
|
152
152
|
custom_id?: string;
|
|
@@ -155,6 +155,10 @@ export type DistrictEvent = {
|
|
|
155
155
|
channel_id: string;
|
|
156
156
|
user_id: string;
|
|
157
157
|
args?: Record<string, unknown>;
|
|
158
|
+
data?: {
|
|
159
|
+
values?: string[];
|
|
160
|
+
fields?: Record<string, string>;
|
|
161
|
+
};
|
|
158
162
|
};
|
|
159
163
|
export interface ReactionEvent {
|
|
160
164
|
spaceId: string;
|
package/package.json
CHANGED