Compare commits

...

12 commits

Author SHA1 Message Date
8e0346dc12
feat: Add UnMarshal 2025-05-14 21:25:27 +09:00
4ee5a8485c
fix: json tag 2025-05-14 21:23:03 +09:00
0e882c3f2c
Merge branch 'componentsv2' of https://github.com/bwmarrin/discordgo into develop 2025-05-14 18:51:41 +09:00
Fedor Lapshin
2a94d95411
feat: add components to unmarshalableMessageComponent.UnmarshalJSON 2025-05-05 13:33:13 +03:00
Fedor Lapshin
bdc047b3f9
feat: implement MarshalJSON 2025-05-05 13:28:28 +03:00
Fedor Lapshin
a1e4f3d201
docs: specify whether component is top-level 2025-05-05 12:05:06 +03:00
Fedor Lapshin
11ab346eaa
godoc fix 2025-04-26 14:20:20 +03:00
Fedor Lapshin
5fd20bb8c2
feat: add docs 2025-04-26 14:17:10 +03:00
Fedor Lapshin
9600402fc1
feat: components v2 structures 2025-04-26 14:05:02 +03:00
Fedor Lapshin
49980810d5
fix id type and add messageflags prefix to IS_COMPONENTS_V2 flag 2025-03-07 22:19:45 +03:00
Fedor Lapshin
4d660d08b9
feat(message): add MessageComponentsV2 flag 2025-03-07 22:16:17 +03:00
Fedor Lapshin
e0f5cdab0a
feat(components): add more types and id field 2025-03-07 22:09:04 +03:00
2 changed files with 326 additions and 1 deletions

View file

@ -18,6 +18,14 @@ const (
RoleSelectMenuComponent ComponentType = 6
MentionableSelectMenuComponent ComponentType = 7
ChannelSelectMenuComponent ComponentType = 8
SectionComponent ComponentType = 9
TextDisplayComponent ComponentType = 10
ThumbnailComponent ComponentType = 11
MediaGalleryComponent ComponentType = 12
FileComponentType ComponentType = 13
SeparatorComponent ComponentType = 14
ContentInventoryEntryComponent ComponentType = 16
ContainerComponent ComponentType = 17
)
// MessageComponent is a base interface for all message components.
@ -50,6 +58,20 @@ func (umc *unmarshalableMessageComponent) UnmarshalJSON(src []byte) error {
umc.MessageComponent = &SelectMenu{}
case TextInputComponent:
umc.MessageComponent = &TextInput{}
case SectionComponent:
umc.MessageComponent = &Section{}
case TextDisplayComponent:
umc.MessageComponent = &TextDisplay{}
case ThumbnailComponent:
umc.MessageComponent = &Thumbnail{}
case MediaGalleryComponent:
umc.MessageComponent = &MediaGallery{}
case FileComponentType:
umc.MessageComponent = &FileComponent{}
case SeparatorComponent:
umc.MessageComponent = &Separator{}
case ContainerComponent:
umc.MessageComponent = &Container{}
default:
return fmt.Errorf("unknown component type: %d", v.Type)
}
@ -66,9 +88,13 @@ func MessageComponentFromJSON(b []byte) (MessageComponent, error) {
return u.MessageComponent, nil
}
// ActionsRow is a container for components within one row.
// ActionsRow is a top-level container component for displaying a row of interactive components.
type ActionsRow struct {
// Can contain Button, SelectMenu and TextInput.
// NOTE: maximum of 5.
Components []MessageComponent `json:"components"`
// Unique identifier for the component; auto populated through increment if not provided.
ID int `json:"id,omitempty"`
}
// MarshalJSON is a method for marshaling ActionsRow to a JSON object.
@ -144,6 +170,8 @@ type Button struct {
CustomID string `json:"custom_id,omitempty"`
// Identifier for a purchasable SKU. Only available when using premium-style buttons.
SKUID string `json:"sku_id,omitempty"`
// Unique identifier for the component; auto populated through increment if not provided.
ID int `json:"id,omitempty"`
}
// MarshalJSON is a method for marshaling Button to a JSON object.
@ -230,6 +258,9 @@ type SelectMenu struct {
// NOTE: Can only be used in SelectMenu with Channel menu type.
ChannelTypes []ChannelType `json:"channel_types,omitempty"`
// Unique identifier for the component; auto populated through increment if not provided.
ID int `json:"id,omitempty"`
}
// Type is a method to get the type of a component.
@ -263,6 +294,9 @@ type TextInput struct {
Required bool `json:"required"`
MinLength int `json:"min_length,omitempty"`
MaxLength int `json:"max_length,omitempty"`
// Unique identifier for the component; auto populated through increment if not provided.
ID int `json:"id,omitempty"`
}
// Type is a method to get the type of a component.
@ -291,3 +325,292 @@ const (
TextInputShort TextInputStyle = 1
TextInputParagraph TextInputStyle = 2
)
// Section is a top-level layout component that allows you to join text contextually with an accessory.
type Section struct {
// Unique identifier for the component; auto populated through increment if not provided.
ID int `json:"id,omitempty"`
// Array of text display components; max of 3.
Components []MessageComponent `json:"components"`
// Can be Button or Thumbnail
Accessory MessageComponent `json:"accessory"`
}
// Type is a method to get the type of a component.
func (Section) Type() ComponentType {
return SectionComponent
}
// MarshalJSON is a method for marshaling Section to a JSON object.
func (s Section) MarshalJSON() ([]byte, error) {
type section Section
return Marshal(struct {
section
Type ComponentType `json:"type"`
}{
section: section(s),
Type: s.Type(),
})
}
// UnmarshalJSON is a method for unmarshaling Section from JSON.
// origin https://github.com/bwmarrin/discordgo/pull/1616
func (s *Section) UnmarshalJSON(data []byte) error {
type sectionAlias Section
aux := struct {
sectionAlias
RawComponents []json.RawMessage `json:"components"`
RawAccessory json.RawMessage `json:"accessory"`
}{}
if err := json.Unmarshal(data, &aux); err != nil {
return err
}
*s = Section(aux.sectionAlias)
s.Components = make([]MessageComponent, len(aux.RawComponents))
for i, raw := range aux.RawComponents {
component, err := MessageComponentFromJSON(raw)
if err != nil {
return fmt.Errorf("failed to unmarshal section component %d: %w", i, err)
}
s.Components[i] = component
}
if len(aux.RawAccessory) > 0 && string(aux.RawAccessory) != "null" {
accessory, err := MessageComponentFromJSON(aux.RawAccessory)
if err != nil {
return fmt.Errorf("failed to unmarshal accessory: %w", err)
}
s.Accessory = accessory
}
return nil
}
// TextDisplay is a top-level component that allows you to add markdown-formatted text to the message.
type TextDisplay struct {
Content string `json:"content"`
}
// Type is a method to get the type of a component.
func (TextDisplay) Type() ComponentType {
return TextDisplayComponent
}
// MarshalJSON is a method for marshaling TextDisplay to a JSON object.
func (t TextDisplay) MarshalJSON() ([]byte, error) {
type textDisplay TextDisplay
return Marshal(struct {
textDisplay
Type ComponentType `json:"type"`
}{
textDisplay: textDisplay(t),
Type: t.Type(),
})
}
// Thumbnail component can be used as an accessory for a section component.
type Thumbnail struct {
// Unique identifier for the component; auto populated through increment if not provided.
ID int `json:"id,omitempty"`
Media UnfurledMediaItem `json:"media"`
Description *string `json:"description,omitempty"`
Spoiler bool `json:"spoiler,omitempty"`
}
// Type is a method to get the type of a component.
func (Thumbnail) Type() ComponentType {
return ThumbnailComponent
}
// MarshalJSON is a method for marshaling Thumbnail to a JSON object.
func (t Thumbnail) MarshalJSON() ([]byte, error) {
type thumbnail Thumbnail
return Marshal(struct {
thumbnail
Type ComponentType `json:"type"`
}{
thumbnail: thumbnail(t),
Type: t.Type(),
})
}
// MediaGallery is a top-level component allows you to group images, videos or gifs into a gallery grid.
type MediaGallery struct {
// Unique identifier for the component; auto populated through increment if not provided.
ID int `json:"id,omitempty"`
// Array of media gallery items; max of 10.
Items []MediaGalleryItem `json:"items"`
}
// Type is a method to get the type of a component.
func (MediaGallery) Type() ComponentType {
return MediaGalleryComponent
}
// MarshalJSON is a method for marshaling MediaGallery to a JSON object.
func (m MediaGallery) MarshalJSON() ([]byte, error) {
type mediaGallery MediaGallery
return Marshal(struct {
mediaGallery
Type ComponentType `json:"type"`
}{
mediaGallery: mediaGallery(m),
Type: m.Type(),
})
}
// MediaGalleryItem represents an item used in MediaGallery.
type MediaGalleryItem struct {
Media UnfurledMediaItem `json:"media"`
Description *string `json:"description,omitempty"`
Spoiler bool `json:"spoiler"`
}
// FileComponent is a top-level component that allows you to display an uploaded file as an attachment to the message and reference it in the component.
type FileComponent struct {
// Unique identifier for the component; auto populated through increment if not provided.
ID int `json:"id,omitempty"`
File UnfurledMediaItem `json:"file"`
Spoiler bool `json:"spoiler"`
}
// Type is a method to get the type of a component.
func (FileComponent) Type() ComponentType {
return FileComponentType
}
// MarshalJSON is a method for marshaling FileComponent to a JSON object.
func (f FileComponent) MarshalJSON() ([]byte, error) {
type fileComponent FileComponent
return Marshal(struct {
fileComponent
Type ComponentType `json:"type"`
}{
fileComponent: fileComponent(f),
Type: f.Type(),
})
}
// SeparatorSpacingSize represents spacing size around the separator.
type SeparatorSpacingSize uint
// Separator spacing sizes.
const (
SeparatorSpacingSizeSmall SeparatorSpacingSize = 1
SeparatorSpacingSizeLarge SeparatorSpacingSize = 2
)
// Separator is a top-level layout component that adds vertical padding and visual division between other components.
type Separator struct {
// Unique identifier for the component; auto populated through increment if not provided.
ID int `json:"id,omitempty"`
Divider *bool `json:"divider,omitempty"`
Spacing *SeparatorSpacingSize `json:"spacing,omitempty"`
}
// Type is a method to get the type of a component.
func (Separator) Type() ComponentType {
return SeparatorComponent
}
// MarshalJSON is a method for marshaling Separator to a JSON object.
func (s Separator) MarshalJSON() ([]byte, error) {
type separator Separator
return Marshal(struct {
separator
Type ComponentType `json:"type"`
}{
separator: separator(s),
Type: s.Type(),
})
}
// Container is a top-level layout component.
// Containers are visually distinct from surrounding components and have an optional customizable color bar (similar to embeds).
type Container struct {
// Unique identifier for the component; auto populated through increment if not provided.
ID int `json:"id,omitempty"`
AccentColor *int `json:"accent_color,omitempty"`
Spoiler bool `json:"spoiler"`
Components []MessageComponent `json:"components"`
}
// Type is a method to get the type of a component.
func (Container) Type() ComponentType {
return ContainerComponent
}
// MarshalJSON is a method for marshaling Container to a JSON object.
func (c Container) MarshalJSON() ([]byte, error) {
type container Container
return Marshal(struct {
container
Type ComponentType `json:"type"`
}{
container: container(c),
Type: c.Type(),
})
}
// UnmarshalJSON is a method for unmarshaling Container from JSON.
// origin https://github.com/bwmarrin/discordgo/pull/1616
func (c *Container) UnmarshalJSON(data []byte) error {
type containerAlias Container
aux := struct {
containerAlias
RawComponents []json.RawMessage `json:"components"`
}{}
if err := json.Unmarshal(data, &aux); err != nil {
return err
}
*c = Container(aux.containerAlias)
c.Components = make([]MessageComponent, len(aux.RawComponents))
for i, raw := range aux.RawComponents {
component, err := MessageComponentFromJSON(raw)
if err != nil {
return fmt.Errorf("failed to parse component at index %d: %w", i, err)
}
c.Components[i] = component
}
return nil
}
// UnfurledMediaItem represents an unfurled media item.
type UnfurledMediaItem struct {
URL string `json:"url"`
}
// UnfurledMediaItemLoadingState is the loading state of the unfurled media item.
type UnfurledMediaItemLoadingState uint
// Unfurled media item loading states.
const (
UnfurledMediaItemLoadingStateUnknown UnfurledMediaItemLoadingState = 0
UnfurledMediaItemLoadingStateLoading UnfurledMediaItemLoadingState = 1
UnfurledMediaItemLoadingStateLoadingSuccess UnfurledMediaItemLoadingState = 2
UnfurledMediaItemLoadingStateLoadedNotFound UnfurledMediaItemLoadingState = 3
)
// ResolvedUnfurledMediaItem represents a resolved unfurled media item.
type ResolvedUnfurledMediaItem struct {
URL string `json:"url"`
ProxyURL string `json:"proxy_url"`
Width int `json:"width"`
Height int `json:"height"`
ContentType string `json:"content_type"`
}

View file

@ -230,6 +230,8 @@ const (
MessageFlagsSuppressNotifications MessageFlags = 1 << 12
// MessageFlagsIsVoiceMessage this message is a voice message.
MessageFlagsIsVoiceMessage MessageFlags = 1 << 13
// MessageFlagsIsComponentsV2 this message uses the new components system. Disables the ability of sending `content` & `embeds`
MessageFlagsIsComponentsV2 MessageFlags = 1 << 15
)
// File stores info about files you e.g. send in messages.