feat(components): File upload component for modals (#4468)

* feat(components): File upload component for modals

* Update comments

upstream has been merged into the file uploads pr

* reverse transform, comment typo fix
This commit is contained in:
Fleny
2025-10-28 20:26:07 +01:00
committed by GitHub
parent 3d2ff13e4d
commit 5867d11415
4 changed files with 116 additions and 1 deletions
@@ -3,6 +3,8 @@ import {
type DiscordButtonComponent,
type DiscordContainerComponent,
type DiscordFileComponent,
type DiscordFileUploadComponent,
type DiscordFileUploadInteractionResponse,
type DiscordLabelComponent,
type DiscordLabelInteractionResponse,
type DiscordMediaGalleryComponent,
@@ -69,6 +71,9 @@ export function transformComponent(bot: Bot, payload: DiscordMessageComponent |
case MessageComponentTypes.Label:
component = transformLabelComponent(bot, payload)
break
case MessageComponentTypes.FileUpload:
component = transformFileUploadComponent(bot, payload)
break
}
return bot.transformers.customizers.component(bot, payload, component)
@@ -294,3 +299,23 @@ function transformLabelComponent(bot: Bot, payload: DiscordLabelComponent | Disc
return label
}
function transformFileUploadComponent(bot: Bot, payload: DiscordFileUploadComponent | DiscordFileUploadInteractionResponse): Component {
const props = bot.transformers.desiredProperties.component
const fileUpload = {} as Component
if (props.type && payload.type) fileUpload.type = payload.type
if (props.id && payload.id) fileUpload.id = payload.id
if (props.customId && payload.custom_id) fileUpload.customId = payload.custom_id
// Check that this is a response
if ('values' in payload) {
if (props.values && payload.values) fileUpload.values = payload.values
} else {
if (props.minValues && payload.min_values) fileUpload.minValues = payload.min_values
if (props.maxValues && payload.max_values) fileUpload.maxValues = payload.max_values
if (props.required && payload.required) fileUpload.required = payload.required
}
return fileUpload
}
@@ -4,6 +4,7 @@ import {
type DiscordButtonComponent,
type DiscordContainerComponent,
type DiscordFileComponent,
type DiscordFileUploadComponent,
type DiscordLabelComponent,
type DiscordMediaGalleryComponent,
type DiscordMediaGalleryItem,
@@ -53,6 +54,8 @@ export function transformComponentToDiscordComponent(
return transformThumbnailComponent(bot, payload)
case MessageComponentTypes.Label:
return transformLabelComponent(bot, payload)
case MessageComponentTypes.FileUpload:
return transformFileUploadComponent(bot, payload)
case MessageComponentTypes.Separator:
case MessageComponentTypes.TextDisplay:
// As of now they are compatible
@@ -223,3 +226,14 @@ function transformLabelComponent(bot: Bot, payload: Component): DiscordLabelComp
component: bot.transformers.reverse.component(bot, payload.component!) as DiscordLabelComponent['component'],
}
}
function transformFileUploadComponent(bot: Bot, payload: Component): DiscordFileUploadComponent {
return {
type: MessageComponentTypes.FileUpload,
id: payload.id,
custom_id: payload.customId!,
max_values: payload.maxValues,
min_values: payload.minValues,
required: payload.required,
}
}
+48 -1
View File
@@ -39,6 +39,8 @@ export enum MessageComponentTypes {
Container = 17,
/** Container associating a label and description with a component */
Label,
/** Component for uploading files */
FileUpload,
}
export type DiscordMessageComponents = DiscordMessageComponent[]
@@ -55,6 +57,7 @@ export type DiscordMessageComponent =
| DiscordContainerComponent
| DiscordFileComponent
| DiscordLabelComponent
| DiscordFileUploadComponent
export type DiscordMessageComponentFromModalInteractionResponse =
| DiscordTextInputInteractionResponse
@@ -547,7 +550,7 @@ export interface DiscordLabelComponent extends DiscordBaseComponent {
*/
description?: string
/** The component within the label */
component: DiscordTextInputComponent | DiscordSelectMenuComponent
component: DiscordTextInputComponent | DiscordSelectMenuComponent | DiscordFileUploadComponent
}
/** https://discord.com/developers/docs/components/reference#label-label-interaction-response-structure */
@@ -563,6 +566,50 @@ export interface DiscordLabelInteractionResponse {
| DiscordRoleSelectInteractionResponseFromModal
| DiscordMentionableSelectInteractionResponseFromModal
| DiscordChannelSelectInteractionResponseFromModal
| DiscordFileUploadInteractionResponse
}
/** https://discord.com/developers/docs/components/reference#file-upload-file-upload-structure */
export interface DiscordFileUploadComponent extends DiscordBaseComponent {
type: MessageComponentTypes.FileUpload
/** The custom id for the file upload */
custom_id: string
/**
* The minimum number of files that must be uploaded
*
* @remarks
* Between 0-10
*
* @default 1
*/
min_values?: number
/** The maximum number of files that can be uploaded
*
* @remarks
* Between 1-10
*
* @default 1
*/
max_values?: number
/**
* Whether this component is required to be filled
*
* @default true
*/
required?: boolean
}
/** https://discord.com/developers/docs/components/reference#file-upload-file-upload-interaction-response-structure */
export interface DiscordFileUploadInteractionResponse {
type: MessageComponentTypes.FileUpload
/** Unique identifier for the component */
id: number
/** The custom id for the file upload */
custom_id: string
/** IDs of the uploaded files found in the resolved data */
values: string[]
}
/** https://discord.com/developers/docs/components/reference#unfurled-media-item-structure */
@@ -29,6 +29,7 @@ export type MessageComponent =
| ContainerComponent
| FileComponent
| LabelComponent
| FileUploadComponent
/** https://discord.com/developers/docs/components/reference#anatomy-of-a-component */
export interface BaseComponent {
@@ -439,4 +440,32 @@ export interface LabelComponent extends BaseComponent {
| RoleSelectComponent
| MentionableSelectComponent
| ChannelSelectComponent
| FileUploadComponent
}
/** https://discord.com/developers/docs/components/reference#file-upload-file-upload-structure */
export interface FileUploadComponent extends BaseComponent {
type: MessageComponentTypes.FileUpload
/** The custom id for the file upload */
customId: string
/**
* The minimum number of files that must be uploaded
*
* @remarks
* Between 0-10
*/
minValues?: number
/** The maximum number of files that can be uploaded
*
* @remarks
* Between 1-10
*/
maxValues?: number
/**
* Whether this component is required to be filled
*
* @default true
*/
required?: boolean
}