diff --git a/components.go b/components.go index 8dd5cdb..a5e8e31 100644 --- a/components.go +++ b/components.go @@ -25,6 +25,7 @@ const ( FileComponentType ComponentType = 13 SeparatorComponent ComponentType = 14 ContainerComponent ComponentType = 17 + LabelComponent ComponentType = 18 ) // MessageComponent is a base interface for all message components. @@ -71,6 +72,8 @@ func (umc *unmarshalableMessageComponent) UnmarshalJSON(src []byte) error { umc.MessageComponent = &Separator{} case ContainerComponent: umc.MessageComponent = &Container{} + case LabelComponent: + umc.MessageComponent = &Label{} default: return fmt.Errorf("unknown component type: %d", v.Type) } @@ -264,6 +267,9 @@ type SelectMenu struct { // Unique identifier for the component; auto populated through increment if not provided. ID int `json:"id,omitempty"` + + // List of values that is only populated when receiving an interaction response; do not fill this manually. + Values []string `json:"values,omitempty"` } // Type is a method to get the type of a component. @@ -578,6 +584,54 @@ func (c Container) MarshalJSON() ([]byte, error) { }) } +// Label is a top-level layout component. +// Labels wrap modal components with text as a label and optional description. +type Label struct { + // Unique identifier for the component; auto populated through increment if not provided. + ID int `json:"id,omitempty"` + Label string `json:"label"` + Description string `json:"description,omitempty"` + Component MessageComponent `json:"component"` +} + +// Type is a method to get the type of a component. +func (Label) Type() ComponentType { + return LabelComponent +} + +// UnmarshalJSON is a method for unmarshaling Label from JSON +func (l *Label) UnmarshalJSON(data []byte) error { + type label Label + + var v struct { + label + RawComponent unmarshalableMessageComponent `json:"component"` + } + + err := json.Unmarshal(data, &v) + if err != nil { + return err + } + + *l = Label(v.label) + l.Component = v.RawComponent.MessageComponent + + return nil +} + +// MarshalJSON is a method for marshaling Label to a JSON object. +func (l Label) MarshalJSON() ([]byte, error) { + type label Label + + return Marshal(struct { + label + Type ComponentType `json:"type"` + }{ + label: label(l), + Type: l.Type(), + }) +} + // UnfurledMediaItem represents an unfurled media item. type UnfurledMediaItem struct { URL string `json:"url"` diff --git a/examples/modals/main.go b/examples/modals/main.go index 6a48cdc..dfd90c7 100644 --- a/examples/modals/main.go +++ b/examples/modals/main.go @@ -48,29 +48,32 @@ var ( Data: &discordgo.InteractionResponseData{ CustomID: "modals_survey_" + i.Interaction.Member.User.ID, Title: "Modals survey", + Flags: discordgo.MessageFlagsIsComponentsV2, Components: []discordgo.MessageComponent{ - discordgo.ActionsRow{ - Components: []discordgo.MessageComponent{ - discordgo.TextInput{ - CustomID: "opinion", - Label: "What is your opinion on them?", - Style: discordgo.TextInputShort, - Placeholder: "Don't be shy, share your opinion with us", - Required: true, - MaxLength: 300, - MinLength: 10, + discordgo.Label{ + Label: "How would you rate them?", + Description: "On a scale from terrible to awesome", + Component: discordgo.SelectMenu{ + MenuType: discordgo.StringSelectMenu, + CustomID: "rating", + Placeholder: "Your rating...", + Options: []discordgo.SelectMenuOption{ + {Label: "Terrible", Value: "terrible"}, + {Label: "Bad", Value: "bad"}, + {Label: "Neutral", Value: "neutral", Default: true}, + {Label: "Good", Value: "good"}, + {Label: "Awesome", Value: "awesome"}, }, }, }, - discordgo.ActionsRow{ - Components: []discordgo.MessageComponent{ - discordgo.TextInput{ - CustomID: "suggestions", - Label: "What would you suggest to improve them?", - Style: discordgo.TextInputParagraph, - Required: false, - MaxLength: 2000, - }, + discordgo.Label{ + Label: "What would you suggest to improve them?", + Description: "Please provide as much info as possible!", + Component: discordgo.TextInput{ + CustomID: "suggestions", + Style: discordgo.TextInputParagraph, + Required: false, + MaxLength: 2000, }, }, }, @@ -113,10 +116,10 @@ func main() { userid := strings.Split(data.CustomID, "_")[2] _, err = s.ChannelMessageSend(*ResultsChannel, fmt.Sprintf( - "Feedback received. From <@%s>\n\n**Opinion**:\n%s\n\n**Suggestions**:\n%s", + "Feedback received. From <@%s>\n\n**Rating**:\n%s\n\n**Suggestions**:\n%s", userid, - data.Components[0].(*discordgo.ActionsRow).Components[0].(*discordgo.TextInput).Value, - data.Components[1].(*discordgo.ActionsRow).Components[0].(*discordgo.TextInput).Value, + data.Components[0].(*discordgo.Label).Component.(*discordgo.SelectMenu).Values[0], + data.Components[1].(*discordgo.Label).Component.(*discordgo.TextInput).Value, )) if err != nil { panic(err) diff --git a/interactions.go b/interactions.go index 1450ad3..c62823b 100644 --- a/interactions.go +++ b/interactions.go @@ -381,16 +381,16 @@ func (ApplicationCommandInteractionData) Type() InteractionType { // MessageComponentInteractionData contains the data of message component interaction. type MessageComponentInteractionData struct { - CustomID string `json:"custom_id"` - ComponentType ComponentType `json:"component_type"` - Resolved MessageComponentInteractionDataResolved `json:"resolved"` + CustomID string `json:"custom_id"` + ComponentType ComponentType `json:"component_type"` + Resolved ComponentInteractionDataResolved `json:"resolved"` // NOTE: Only filled when ComponentType is SelectMenuComponent (3). Otherwise is nil. Values []string `json:"values"` } -// MessageComponentInteractionDataResolved contains the resolved data of selected option. -type MessageComponentInteractionDataResolved struct { +// ComponentInteractionDataResolved contains the resolved data of selected option. +type ComponentInteractionDataResolved struct { Users map[string]*User `json:"users"` Members map[string]*Member `json:"members"` Roles map[string]*Role `json:"roles"` @@ -404,8 +404,9 @@ func (MessageComponentInteractionData) Type() InteractionType { // ModalSubmitInteractionData contains the data of modal submit interaction. type ModalSubmitInteractionData struct { - CustomID string `json:"custom_id"` - Components []MessageComponent `json:"-"` + CustomID string `json:"custom_id"` + Components []MessageComponent `json:"-"` + Resolved ComponentInteractionDataResolved `json:"resolved"` } // Type returns the type of interaction data.