components.go 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. package discordgo
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. )
  6. // ComponentType is type of component.
  7. type ComponentType uint
  8. // MessageComponent types.
  9. const (
  10. ActionsRowComponent ComponentType = 1
  11. ButtonComponent ComponentType = 2
  12. SelectMenuComponent ComponentType = 3
  13. )
  14. // MessageComponent is a base interface for all message components.
  15. type MessageComponent interface {
  16. json.Marshaler
  17. Type() ComponentType
  18. }
  19. type unmarshalableMessageComponent struct {
  20. MessageComponent
  21. }
  22. // UnmarshalJSON is a helper function to unmarshal MessageComponent object.
  23. func (umc *unmarshalableMessageComponent) UnmarshalJSON(src []byte) error {
  24. var v struct {
  25. Type ComponentType `json:"type"`
  26. }
  27. err := json.Unmarshal(src, &v)
  28. if err != nil {
  29. return err
  30. }
  31. switch v.Type {
  32. case ActionsRowComponent:
  33. umc.MessageComponent = &ActionsRow{}
  34. case ButtonComponent:
  35. umc.MessageComponent = &Button{}
  36. case SelectMenuComponent:
  37. umc.MessageComponent = &SelectMenu{}
  38. default:
  39. return fmt.Errorf("unknown component type: %d", v.Type)
  40. }
  41. return json.Unmarshal(src, umc.MessageComponent)
  42. }
  43. func MessageComponentFromJSON(b []byte) (MessageComponent, error) {
  44. var u unmarshalableMessageComponent
  45. err := u.UnmarshalJSON(b)
  46. if err != nil {
  47. return nil, fmt.Errorf("failed to unmarshal into MessageComponent: %w", err)
  48. }
  49. return u.MessageComponent, nil
  50. }
  51. // ActionsRow is a container for components within one row.
  52. type ActionsRow struct {
  53. Components []MessageComponent `json:"components"`
  54. }
  55. // MarshalJSON is a method for marshaling ActionsRow to a JSON object.
  56. func (r ActionsRow) MarshalJSON() ([]byte, error) {
  57. type actionsRow ActionsRow
  58. return json.Marshal(struct {
  59. actionsRow
  60. Type ComponentType `json:"type"`
  61. }{
  62. actionsRow: actionsRow(r),
  63. Type: r.Type(),
  64. })
  65. }
  66. // UnmarshalJSON is a helper function to unmarshal Actions Row.
  67. func (r *ActionsRow) UnmarshalJSON(data []byte) error {
  68. var v struct {
  69. RawComponents []unmarshalableMessageComponent `json:"components"`
  70. }
  71. err := json.Unmarshal(data, &v)
  72. if err != nil {
  73. return err
  74. }
  75. r.Components = make([]MessageComponent, len(v.RawComponents))
  76. for i, v := range v.RawComponents {
  77. r.Components[i] = v.MessageComponent
  78. }
  79. return err
  80. }
  81. // Type is a method to get the type of a component.
  82. func (r ActionsRow) Type() ComponentType {
  83. return ActionsRowComponent
  84. }
  85. // ButtonStyle is style of button.
  86. type ButtonStyle uint
  87. // Button styles.
  88. const (
  89. // PrimaryButton is a button with blurple color.
  90. PrimaryButton ButtonStyle = 1
  91. // SecondaryButton is a button with grey color.
  92. SecondaryButton ButtonStyle = 2
  93. // SuccessButton is a button with green color.
  94. SuccessButton ButtonStyle = 3
  95. // DangerButton is a button with red color.
  96. DangerButton ButtonStyle = 4
  97. // LinkButton is a special type of button which navigates to a URL. Has grey color.
  98. LinkButton ButtonStyle = 5
  99. )
  100. // ComponentEmoji represents button emoji, if it does have one.
  101. type ComponentEmoji struct {
  102. Name string `json:"name,omitempty"`
  103. ID string `json:"id,omitempty"`
  104. Animated bool `json:"animated,omitempty"`
  105. }
  106. // Button represents button component.
  107. type Button struct {
  108. Label string `json:"label"`
  109. Style ButtonStyle `json:"style"`
  110. Disabled bool `json:"disabled"`
  111. Emoji ComponentEmoji `json:"emoji"`
  112. // NOTE: Only button with LinkButton style can have link. Also, URL is mutually exclusive with CustomID.
  113. URL string `json:"url,omitempty"`
  114. CustomID string `json:"custom_id,omitempty"`
  115. }
  116. // MarshalJSON is a method for marshaling Button to a JSON object.
  117. func (b Button) MarshalJSON() ([]byte, error) {
  118. type button Button
  119. if b.Style == 0 {
  120. b.Style = PrimaryButton
  121. }
  122. return json.Marshal(struct {
  123. button
  124. Type ComponentType `json:"type"`
  125. }{
  126. button: button(b),
  127. Type: b.Type(),
  128. })
  129. }
  130. // Type is a method to get the type of a component.
  131. func (Button) Type() ComponentType {
  132. return ButtonComponent
  133. }
  134. // SelectMenuOption represents an option for a select menu.
  135. type SelectMenuOption struct {
  136. Label string `json:"label,omitempty"`
  137. Value string `json:"value"`
  138. Description string `json:"description"`
  139. Emoji ComponentEmoji `json:"emoji"`
  140. // Determines whenever option is selected by default or not.
  141. Default bool `json:"default"`
  142. }
  143. // SelectMenu represents select menu component.
  144. type SelectMenu struct {
  145. CustomID string `json:"custom_id,omitempty"`
  146. // The text which will be shown in the menu if there's no default options or all options was deselected and component was closed.
  147. Placeholder string `json:"placeholder"`
  148. // This value determines the minimal amount of selected items in the menu.
  149. MinValues int `json:"min_values,omitempty"`
  150. // This value determines the maximal amount of selected items in the menu.
  151. // If MaxValues or MinValues are greater than one then the user can select multiple items in the component.
  152. MaxValues int `json:"max_values,omitempty"`
  153. Options []SelectMenuOption `json:"options"`
  154. }
  155. // Type is a method to get the type of a component.
  156. func (SelectMenu) Type() ComponentType {
  157. return SelectMenuComponent
  158. }
  159. // MarshalJSON is a method for marshaling SelectMenu to a JSON object.
  160. func (m SelectMenu) MarshalJSON() ([]byte, error) {
  161. type selectMenu SelectMenu
  162. return json.Marshal(struct {
  163. selectMenu
  164. Type ComponentType `json:"type"`
  165. }{
  166. selectMenu: selectMenu(m),
  167. Type: m.Type(),
  168. })
  169. }