@kevlid/discordmenus 0.0.2

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.
@@ -0,0 +1,379 @@
1
+ const { decodeId, Presets } = require("../utils/customIds");
2
+ const { EphemeralMessageFlag } = require("../utils/constants");
3
+ const { OptionTypes, ResponseTypes } = require("../utils/types");
4
+ const {
5
+ arrayClone,
6
+ asObject,
7
+ objectDefaultsFromKeys,
8
+ objectListPropertyKey,
9
+ objectListItemFailsRequired,
10
+ listJumpSize,
11
+ shapeObjectListItem,
12
+ normalizeObjectListItems,
13
+ } = require("../utils/helpers");
14
+
15
+ function ephemeral(content) {
16
+ return {
17
+ type: ResponseTypes.ChannelMessageWithSource,
18
+ data: { flags: EphemeralMessageFlag, content },
19
+ };
20
+ }
21
+
22
+ function updateMessage(data) {
23
+ return { type: ResponseTypes.UpdateMessage, data };
24
+ }
25
+
26
+ function openModal(data) {
27
+ return { type: ResponseTypes.Modal, data };
28
+ }
29
+
30
+ async function handleListBranch({
31
+ menu,
32
+ menu_key,
33
+ renderMenu,
34
+ values,
35
+ options,
36
+ category,
37
+ page,
38
+ userId,
39
+ guildId,
40
+ }) {
41
+ const optionKey = values[0];
42
+ const subAction = values[2];
43
+ const sub = parseInt(options.get("sub") ?? 0);
44
+ const option = menu.getOption(category, page, optionKey);
45
+ const objectItems = option && option.itemType === OptionTypes.Object;
46
+ const menuCtx = { category, index: page, userId, guildId };
47
+
48
+ switch (subAction) {
49
+ case Presets.view:
50
+ if (objectItems) {
51
+ return updateMessage(
52
+ await menu.renderListObjectItemPage(optionKey, 0, { ...menuCtx, listPage: 0 }),
53
+ );
54
+ }
55
+ return updateMessage(await menu.renderListPage(optionKey, 0, menuCtx));
56
+
57
+ case Presets.nav: {
58
+ const targetPage = parseInt(values[3] ?? 0);
59
+ return updateMessage(await menu.renderListPage(optionKey, targetPage, menuCtx));
60
+ }
61
+
62
+ case Presets.edit: {
63
+ const itemIndex = parseInt(values[3]);
64
+ if (objectItems) {
65
+ return updateMessage(
66
+ await menu.renderListObjectItemPage(optionKey, itemIndex, { ...menuCtx, listPage: sub }),
67
+ );
68
+ }
69
+ return openModal(await menu.renderListModal(optionKey, itemIndex, { ...menuCtx, sub }));
70
+ }
71
+
72
+ case Presets.add:
73
+ if (objectItems) {
74
+ const props = option.itemConfig.properties;
75
+ const addItems = normalizeObjectListItems(
76
+ props,
77
+ arrayClone(await menu.get(optionKey, { guildId, userId })),
78
+ );
79
+ addItems.push(shapeObjectListItem(props, {}));
80
+ await menu.save(optionKey, addItems, { guildId, userId });
81
+ return updateMessage(
82
+ await menu.renderListObjectItemPage(optionKey, addItems.length - 1, {
83
+ ...menuCtx,
84
+ listPage: sub,
85
+ }),
86
+ );
87
+ }
88
+ return openModal(await menu.renderListModal(optionKey, null, { ...menuCtx, sub }));
89
+
90
+ case Presets.listItemView: {
91
+ const itemIndex = parseInt(values[3]);
92
+ return updateMessage(
93
+ await menu.renderListObjectItemPage(optionKey, itemIndex, { ...menuCtx, listPage: sub }),
94
+ );
95
+ }
96
+
97
+ case Presets.previousCategory:
98
+ case Presets.nextCategory:
99
+ if (objectItems) {
100
+ const jumpItems = arrayClone(await menu.get(optionKey, { guildId, userId }));
101
+ const currentItemIndex = parseInt(options.get("item") ?? 0);
102
+ const delta = subAction === Presets.previousCategory ? -listJumpSize(jumpItems.length) : listJumpSize(jumpItems.length);
103
+ return updateMessage(
104
+ await menu.renderListObjectItemPage(optionKey, currentItemIndex + delta, {
105
+ ...menuCtx,
106
+ listPage: sub,
107
+ }),
108
+ );
109
+ }
110
+ return updateMessage(await menu.renderListPage(optionKey, sub, menuCtx));
111
+
112
+ case Presets.listItemDone: {
113
+ const itemIndex = parseInt(options.get("item") ?? -1);
114
+ if (objectItems && itemIndex >= 0) {
115
+ const doneItems = arrayClone(await menu.get(optionKey, { guildId, userId }));
116
+ const currentItem = doneItems[itemIndex];
117
+ if (objectListItemFailsRequired(option, currentItem)) {
118
+ doneItems.splice(itemIndex, 1);
119
+ await menu.save(
120
+ optionKey,
121
+ normalizeObjectListItems(option.itemConfig.properties, doneItems),
122
+ { guildId, userId },
123
+ );
124
+ }
125
+ return updateMessage(await renderMenu(menu_key, menuCtx));
126
+ }
127
+ return updateMessage(await menu.renderListPage(optionKey, sub, menuCtx));
128
+ }
129
+
130
+ case Presets.listItemField: {
131
+ const itemIndex = parseInt(values[3]);
132
+ const propertyKey = objectListPropertyKey(option, values[4]);
133
+ return openModal(
134
+ await menu.renderListObjectItemModal(optionKey, propertyKey, itemIndex, {
135
+ ...menuCtx,
136
+ sub,
137
+ }),
138
+ );
139
+ }
140
+
141
+ case Presets.listItemBoolToggle: {
142
+ const itemIndex = parseInt(values[3]);
143
+ const propertyKey = objectListPropertyKey(option, values[4]);
144
+ const newBoolValue = values[5] === "true";
145
+ const props = option.itemConfig.properties;
146
+ const boolItems = normalizeObjectListItems(
147
+ props,
148
+ arrayClone(await menu.get(optionKey, { guildId, userId })),
149
+ );
150
+ boolItems[itemIndex] = shapeObjectListItem(props, {
151
+ ...asObject(boolItems[itemIndex]),
152
+ [propertyKey]: newBoolValue,
153
+ });
154
+ await menu.save(optionKey, boolItems, { guildId, userId });
155
+ return updateMessage(
156
+ await menu.renderListObjectItemPage(optionKey, itemIndex, { ...menuCtx, listPage: sub }),
157
+ );
158
+ }
159
+
160
+ case Presets.delete: {
161
+ const itemIndex = parseInt(values[3]);
162
+ const props = option.itemConfig.properties;
163
+ let deleteItems = arrayClone(await menu.get(optionKey, { guildId, userId }));
164
+ if (objectItems) {
165
+ deleteItems = normalizeObjectListItems(props, deleteItems);
166
+ }
167
+ deleteItems.splice(itemIndex, 1);
168
+ await menu.save(optionKey, deleteItems, { guildId, userId });
169
+ if (objectItems) {
170
+ if (deleteItems.length <= 0) {
171
+ return updateMessage(await renderMenu(menu_key, menuCtx));
172
+ }
173
+ const nextIndex = Math.max(0, Math.min(itemIndex, deleteItems.length - 1));
174
+ return updateMessage(
175
+ await menu.renderListObjectItemPage(optionKey, nextIndex, { ...menuCtx, listPage: sub }),
176
+ );
177
+ }
178
+ return updateMessage(await menu.renderListPage(optionKey, sub, menuCtx));
179
+ }
180
+
181
+ case Presets.done:
182
+ return updateMessage(await renderMenu(menu_key, menuCtx));
183
+
184
+ default:
185
+ return null;
186
+ }
187
+ }
188
+
189
+ async function handleObjectBranch({
190
+ menu,
191
+ menu_key,
192
+ renderMenu,
193
+ values,
194
+ options,
195
+ category,
196
+ page,
197
+ userId,
198
+ guildId,
199
+ }) {
200
+ const objectKey = values[0];
201
+ const subAction = values[2];
202
+ const sub = parseInt(options.get("sub") ?? 0);
203
+ const objectPage = parseInt(options.get("op") ?? 0);
204
+ const menuCtx = { category, index: page, userId, guildId };
205
+ const objectCtx = { ...menuCtx, objectPage };
206
+
207
+ if (subAction === Presets.view) {
208
+ return updateMessage(await menu.renderObjectPage(objectKey, objectCtx));
209
+ }
210
+ if (subAction === Presets.nav) {
211
+ const targetObjectPage = parseInt(values[3] ?? 0);
212
+ return updateMessage(await menu.renderObjectPage(objectKey, { ...menuCtx, objectPage: targetObjectPage }));
213
+ }
214
+ if (subAction === Presets.done) {
215
+ return updateMessage(await renderMenu(menu_key, menuCtx));
216
+ }
217
+ if (subAction === Presets.subBoolean) {
218
+ const subKey = values[3];
219
+ const newValue = values[4] === "true";
220
+ const boolObjectOption = menu.getOption(category, page, objectKey);
221
+ const baseObj = asObject(await menu.get(objectKey, { guildId, userId }));
222
+ const defaults = boolObjectOption ? objectDefaultsFromKeys(boolObjectOption.options) : {};
223
+ const updatedObj = Object.assign(defaults, baseObj);
224
+ updatedObj[subKey] = newValue;
225
+ await menu.save(objectKey, updatedObj, { guildId, userId });
226
+ return updateMessage(await menu.renderObjectPage(objectKey, objectCtx));
227
+ }
228
+ if (subAction === Presets.subModal) {
229
+ const subKey = values[3];
230
+ return openModal(await menu.renderObjectModal(objectKey, subKey, { ...menuCtx, objectPage }));
231
+ }
232
+ if (subAction !== Presets.subList) {
233
+ return null;
234
+ }
235
+
236
+ const subKey = values[3];
237
+ const listAction = values[4];
238
+ const objectOption = menu.getOption(category, page, objectKey);
239
+ const subOption = objectOption?.options.find(o => o.key === subKey);
240
+
241
+ if (listAction === Presets.view) {
242
+ return updateMessage(
243
+ await menu.renderObjectListPage(objectKey, subKey, 0, { ...menuCtx, objectPage }),
244
+ );
245
+ }
246
+ if (listAction === Presets.nav) {
247
+ const targetPage = parseInt(values[5] ?? 0);
248
+ return updateMessage(
249
+ await menu.renderObjectListPage(objectKey, subKey, targetPage, { ...menuCtx, objectPage }),
250
+ );
251
+ }
252
+ if (listAction === Presets.done) {
253
+ return updateMessage(await menu.renderObjectPage(objectKey, objectCtx));
254
+ }
255
+ if (listAction === Presets.add) {
256
+ return openModal(
257
+ await menu.renderObjectListModal(objectKey, subKey, null, {
258
+ ...menuCtx,
259
+ sub,
260
+ objectPage,
261
+ }),
262
+ );
263
+ }
264
+ if (listAction === Presets.edit) {
265
+ const itemIndex = parseInt(values[5]);
266
+ return openModal(
267
+ await menu.renderObjectListModal(objectKey, subKey, itemIndex, {
268
+ ...menuCtx,
269
+ sub,
270
+ objectPage,
271
+ }),
272
+ );
273
+ }
274
+ if (listAction === Presets.delete) {
275
+ const itemIndex = parseInt(values[5]);
276
+ const obj = asObject(await menu.get(objectKey, { guildId, userId }));
277
+ const items = arrayClone(obj[subKey]);
278
+ items.splice(itemIndex, 1);
279
+ await menu.save(objectKey, Object.assign({}, obj, { [subKey]: items }), { guildId, userId });
280
+ return updateMessage(
281
+ await menu.renderObjectListPage(objectKey, subKey, sub, { ...menuCtx, objectPage }),
282
+ );
283
+ }
284
+ return null;
285
+ }
286
+
287
+ async function handleComponent(interaction, menu, menu_key, renderMenu) {
288
+ const guildId = interaction.guildId ?? null;
289
+ const interactionData = interaction.data ?? {};
290
+ const customId = interactionData.custom_id;
291
+ if (!customId) {
292
+ throw new Error("Invalid interaction payload: missing custom_id");
293
+ }
294
+ const { values, options } = decodeId(customId);
295
+ const userId = interaction.member?.user?.id ?? interaction.user?.id ?? null;
296
+
297
+ if (values.length <= 0) {
298
+ throw new Error("Invalid custom ID");
299
+ }
300
+
301
+ if (options.get("u") && String(options.get("u")) !== String(userId)) {
302
+ return ephemeral("This menu doesn't belong to you.");
303
+ }
304
+
305
+ if (menu.permissions.length > 0 && values[1] !== Presets.nav) {
306
+ const memberPerms = BigInt(interaction.member?.permissions ?? 0);
307
+ const allowed = menu.permissions.some(stack =>
308
+ stack.every(p => (memberPerms & BigInt(p)) === BigInt(p)),
309
+ );
310
+ if (!allowed) {
311
+ return ephemeral("You are missing the required permissions");
312
+ }
313
+ }
314
+
315
+ const category = parseInt(options.get("cat") ?? 0);
316
+ const page = parseInt(options.get("page") ?? 0);
317
+ const action = values[1];
318
+
319
+ let result;
320
+
321
+ if (action === Presets.nav) {
322
+ result = updateMessage(
323
+ await renderMenu(menu_key, { category, index: page, userId, guildId }),
324
+ );
325
+ } else if (action === OptionTypes.String || action === OptionTypes.Number) {
326
+ result = openModal(await menu.renderModal(values[0], { category, index: page, guildId }));
327
+ } else if (action === OptionTypes.Boolean) {
328
+ await menu.save(values[0], values[2] === "true", { guildId, userId });
329
+ result = updateMessage(
330
+ await renderMenu(menu_key, { category, index: page, userId, guildId }),
331
+ );
332
+ } else if (action === OptionTypes.List) {
333
+ result = await handleListBranch({
334
+ menu,
335
+ menu_key,
336
+ renderMenu,
337
+ values,
338
+ options,
339
+ category,
340
+ page,
341
+ userId,
342
+ guildId,
343
+ });
344
+ } else if (action === OptionTypes.Object) {
345
+ result = await handleObjectBranch({
346
+ menu,
347
+ menu_key,
348
+ renderMenu,
349
+ values,
350
+ options,
351
+ category,
352
+ page,
353
+ userId,
354
+ guildId,
355
+ });
356
+ } else if (
357
+ action === OptionTypes.StringSelect ||
358
+ action === OptionTypes.UserSelect ||
359
+ action === OptionTypes.RoleSelect ||
360
+ action === OptionTypes.MentionableSelect ||
361
+ action === OptionTypes.ChannelSelect
362
+ ) {
363
+ const optionKey = values[0];
364
+ const selected = interactionData.values ?? [];
365
+ const opt = menu.getOption(category, page, optionKey);
366
+ const saveValue = opt && opt.maxValues === 1 ? selected[0] ?? null : selected;
367
+ await menu.save(optionKey, saveValue, { guildId, userId });
368
+ result = updateMessage(
369
+ await renderMenu(menu_key, { category, index: page, userId, guildId }),
370
+ );
371
+ }
372
+
373
+ if (result == null || result.type == null) {
374
+ throw new Error(`Unhandled component action "${action}"`);
375
+ }
376
+ return result;
377
+ }
378
+
379
+ module.exports = { handleComponent };
@@ -0,0 +1,231 @@
1
+ const { decodeId, Presets } = require("../utils/customIds");
2
+ const { EphemeralMessageFlag } = require("../utils/constants");
3
+ const { OptionTypes, ResponseTypes } = require("../utils/types");
4
+ const { parseModal } = require("../utils/parseModal");
5
+ const {
6
+ arrayClone,
7
+ asObject,
8
+ objectDefaultsFromKeys,
9
+ shapeObjectListItem,
10
+ normalizeObjectListItems,
11
+ } = require("../utils/helpers");
12
+
13
+ function updateMessage(data) {
14
+ return { type: ResponseTypes.UpdateMessage, data };
15
+ }
16
+
17
+ function ephemeral(content) {
18
+ return {
19
+ type: ResponseTypes.ChannelMessageWithSource,
20
+ data: { flags: EphemeralMessageFlag, content },
21
+ };
22
+ }
23
+
24
+ function requiredContent(title) {
25
+ return ephemeral(`**${title}** is required.`);
26
+ }
27
+
28
+ async function handleListModal(menu, values, options, rawValue, category, page, guildId, userId) {
29
+ const optionKey = values[0];
30
+ const subAction = values[2];
31
+ const sub = parseInt(options.get("sub") ?? 0);
32
+ const menuCtx = { category, index: page, userId, guildId };
33
+
34
+ if (subAction === Presets.listItemModal) {
35
+ const propertyToken = values[3];
36
+ const objItemIndex = parseInt(options.get("item") ?? 0);
37
+ const option = menu.getOption(category, page, optionKey);
38
+ if (!option) {
39
+ throw new Error(`Option "${optionKey}" not found`);
40
+ }
41
+ const props = option.itemConfig.properties;
42
+ const objItems = normalizeObjectListItems(props, arrayClone(await menu.get(optionKey, { guildId, userId })));
43
+ let property;
44
+ const propertyIndex = parseInt(propertyToken, 10);
45
+ if (!Number.isNaN(propertyIndex)) {
46
+ property = option.itemConfig.properties[propertyIndex] ?? null;
47
+ } else {
48
+ property = option.itemConfig.properties.find(p => p.key === propertyToken) ?? null;
49
+ }
50
+ if (!property) {
51
+ throw new Error(`Property "${propertyToken}" not found in ObjectList "${optionKey}"`);
52
+ }
53
+ let parsedPropertyValue;
54
+ if (property.itemType === OptionTypes.String) {
55
+ parsedPropertyValue = rawValue;
56
+ } else if (property.itemType === OptionTypes.Number) {
57
+ parsedPropertyValue = parseFloat(rawValue);
58
+ if (Number.isNaN(parsedPropertyValue)) {
59
+ throw new Error(`"${rawValue}" is not a valid number`);
60
+ }
61
+ } else {
62
+ throw new Error(`Property type "${property.itemType}" does not support modal input`);
63
+ }
64
+ objItems[objItemIndex] = shapeObjectListItem(props, {
65
+ ...asObject(objItems[objItemIndex]),
66
+ [property.key]: parsedPropertyValue,
67
+ });
68
+ await menu.save(optionKey, objItems, { guildId, userId });
69
+ return updateMessage(
70
+ await menu.renderListObjectItemPage(optionKey, objItemIndex, { ...menuCtx, listPage: sub }),
71
+ );
72
+ }
73
+
74
+ const option = menu.getOption(category, page, optionKey);
75
+ if (!option) {
76
+ throw new Error(`Option "${optionKey}" not found`);
77
+ }
78
+ const items = arrayClone(await menu.get(optionKey, { guildId, userId }));
79
+ let parsedValue;
80
+ if (option.itemType === OptionTypes.String) {
81
+ parsedValue = rawValue;
82
+ } else if (option.itemType === OptionTypes.Number) {
83
+ parsedValue = parseFloat(rawValue);
84
+ if (Number.isNaN(parsedValue)) {
85
+ throw new Error(`"${rawValue}" is not a valid number`);
86
+ }
87
+ } else {
88
+ throw new Error(`Item type "${option.itemType}" does not support modal input`);
89
+ }
90
+ const itemIndex = values[3] != null ? parseInt(values[3], 10) : null;
91
+ if (subAction === Presets.edit) {
92
+ items[itemIndex] = parsedValue;
93
+ } else if (subAction === Presets.add) {
94
+ items.push(parsedValue);
95
+ } else {
96
+ throw new Error(`Unknown list sub-action "${subAction}"`);
97
+ }
98
+ await menu.save(optionKey, items, { guildId, userId });
99
+ return updateMessage(await menu.renderListPage(optionKey, sub, menuCtx));
100
+ }
101
+
102
+ async function handleObjectModal(menu, values, options, rawValue, category, page, guildId, userId) {
103
+ const optionKey = values[0];
104
+ const action = values[2];
105
+ const subKey = values[3];
106
+ const sub = parseInt(options.get("sub") ?? 0);
107
+ const objectPage = parseInt(options.get("op") ?? 0);
108
+ const menuCtx = { category, index: page, userId, guildId, objectPage };
109
+
110
+ const option = menu.getOption(category, page, optionKey);
111
+ if (!option) {
112
+ throw new Error(`Object option "${optionKey}" not found`);
113
+ }
114
+
115
+ if (action === Presets.subModal) {
116
+ const subOption = option.options.find(o => o.key === subKey);
117
+ if (!subOption) {
118
+ throw new Error(`Sub-option "${subKey}" not found`);
119
+ }
120
+ let parsedValue;
121
+ if (subOption.type === OptionTypes.String) {
122
+ if (rawValue === "") {
123
+ if (subOption.required) {
124
+ return requiredContent(subOption.title);
125
+ }
126
+ parsedValue = null;
127
+ } else {
128
+ parsedValue = rawValue;
129
+ }
130
+ } else if (subOption.type === OptionTypes.Number) {
131
+ if (rawValue === "") {
132
+ if (subOption.required) {
133
+ return requiredContent(subOption.title);
134
+ }
135
+ parsedValue = null;
136
+ } else {
137
+ parsedValue = parseFloat(rawValue);
138
+ if (Number.isNaN(parsedValue)) {
139
+ throw new Error(`"${rawValue}" is not a valid number`);
140
+ }
141
+ }
142
+ } else {
143
+ throw new Error(`Sub-option type "${subOption.type}" does not support modal input`);
144
+ }
145
+ const baseObj = asObject(await menu.get(optionKey, { guildId, userId }));
146
+ const defaults = objectDefaultsFromKeys(option.options);
147
+ const updatedObj = Object.assign(defaults, baseObj);
148
+ updatedObj[subKey] = parsedValue;
149
+ await menu.save(optionKey, updatedObj, { guildId, userId });
150
+ return updateMessage(await menu.renderObjectPage(optionKey, menuCtx));
151
+ }
152
+
153
+ if (action === Presets.subListModal) {
154
+ const listAction = values[4];
155
+ const itemIndex = values[5] != null ? parseInt(values[5], 10) : null;
156
+ const subOption = option.options.find(o => o.key === subKey);
157
+ if (!subOption) {
158
+ throw new Error(`Sub-option "${subKey}" not found`);
159
+ }
160
+ const baseObj = asObject(await menu.get(optionKey, { guildId, userId }));
161
+ const items = arrayClone(baseObj[subKey]);
162
+ let parsedValue;
163
+ if (subOption.itemType === OptionTypes.String) {
164
+ parsedValue = rawValue;
165
+ } else if (subOption.itemType === OptionTypes.Number) {
166
+ parsedValue = parseFloat(rawValue);
167
+ if (Number.isNaN(parsedValue)) {
168
+ throw new Error("Invalid number");
169
+ }
170
+ } else {
171
+ throw new Error(`Sub-option item type "${subOption.itemType}" does not support modal input`);
172
+ }
173
+ if (listAction === Presets.edit) {
174
+ items[itemIndex] = parsedValue;
175
+ } else if (listAction === Presets.add) {
176
+ items.push(parsedValue);
177
+ } else {
178
+ throw new Error(`Unknown list action "${listAction}"`);
179
+ }
180
+ await menu.save(optionKey, Object.assign({}, baseObj, { [subKey]: items }), { guildId, userId });
181
+ return updateMessage(
182
+ await menu.renderObjectListPage(optionKey, subKey, sub, menuCtx),
183
+ );
184
+ }
185
+
186
+ throw new Error(`Unknown object action "${action}"`);
187
+ }
188
+
189
+ async function handleModal(interaction, menu, menu_key, renderMenu) {
190
+ const guildId = interaction.guildId ?? null;
191
+ const interactionData = interaction.data ?? {};
192
+ const customId = interactionData.custom_id;
193
+ if (!customId) {
194
+ throw new Error("Invalid interaction payload: missing custom_id");
195
+ }
196
+ const { options } = decodeId(customId);
197
+ const userId = interaction.member?.user?.id ?? interaction.user?.id ?? null;
198
+ const category = parseInt(options.get("cat") ?? 0);
199
+ const page = parseInt(options.get("page") ?? 0);
200
+ const menuCtx = { category, index: page, userId, guildId };
201
+
202
+ const compValues = parseModal(interactionData.components);
203
+ if (compValues.length <= 0) {
204
+ throw new Error("Invalid modal submission");
205
+ }
206
+ const { values } = decodeId(compValues[0].customId);
207
+ const [, optionType] = values;
208
+ const rawValue = compValues[0].value.trim();
209
+
210
+ if (optionType === OptionTypes.List) {
211
+ return handleListModal(menu, values, options, rawValue, category, page, guildId, userId);
212
+ }
213
+ if (optionType === OptionTypes.Object) {
214
+ return handleObjectModal(menu, values, options, rawValue, category, page, guildId, userId);
215
+ }
216
+ if (optionType === OptionTypes.String) {
217
+ await menu.save(values[0], rawValue, { guildId, userId });
218
+ return updateMessage(await renderMenu(menu_key, menuCtx));
219
+ }
220
+ if (optionType === OptionTypes.Number) {
221
+ const value = parseFloat(rawValue);
222
+ if (Number.isNaN(value)) {
223
+ throw new Error("Invalid number");
224
+ }
225
+ await menu.save(values[0], value, { guildId, userId });
226
+ return updateMessage(await renderMenu(menu_key, menuCtx));
227
+ }
228
+ throw new Error(`Option type "${optionType}" does not support modal input`);
229
+ }
230
+
231
+ module.exports = { handleModal };
package/src/index.js ADDED
@@ -0,0 +1,19 @@
1
+ const { MenuManager } = require("./menuManager");
2
+ const { MenuBuilder } = require("./menuBuilder");
3
+ const { OptionTypes } = require("./utils/types");
4
+ const { CustomIdPrefix, EphemeralMessageFlag } = require("./utils/constants");
5
+ const { MenuStorage, MemoryMenuStorage } = require("./utils/storage");
6
+ const { normalizeInteraction, fromEris, fromDiscordJS } = require("./utils/adapters");
7
+
8
+ module.exports = {
9
+ MenuManager,
10
+ MenuBuilder,
11
+ OptionTypes,
12
+ CustomIdPrefix,
13
+ EphemeralMessageFlag,
14
+ MenuStorage,
15
+ MemoryMenuStorage,
16
+ normalizeInteraction,
17
+ fromEris,
18
+ fromDiscordJS,
19
+ }