3
3
from functools import partial
4
4
from typing import TYPE_CHECKING , ClassVar , Iterator , TypeVar
5
5
6
- from ..colour import Colour
7
6
from ..components import ActionRow as ActionRowComponent
8
- from ..components import Container as ContainerComponent
9
- from ..components import _component_factory
10
- from ..enums import ComponentType , SeparatorSpacingSize
7
+ from ..components import _component_factory , SelectOption
8
+ from ..enums import ComponentType , ButtonStyle , ChannelType
11
9
from ..utils import find , get
12
10
from .file import File
11
+ from .button import Button
12
+ from .select import Select
13
13
from .item import Item , ItemCallbackType
14
- from .media_gallery import MediaGallery
15
- from .section import Section
16
- from .separator import Separator
17
- from .text_display import TextDisplay
18
14
from .view import _walk_all_components
19
15
20
16
__all__ = ("Container" ,)
21
17
22
18
if TYPE_CHECKING :
23
19
from typing_extensions import Self
24
20
25
- from ..types .components import ContainerComponent as ContainerComponentPayload
21
+ from ..emoji import AppEmoji , GuildEmoji
22
+ from ..types .components import ActionRow as ActionRowPayload
23
+ from ..partial_emoji import PartialEmoji , _EmojiTag
26
24
from .view import View
27
25
28
26
29
- AC = TypeVar ("A" , bound = "ActionRow" )
27
+ A = TypeVar ("A" , bound = "ActionRow" )
30
28
V = TypeVar ("V" , bound = "View" , covariant = True )
31
29
32
30
33
31
class ActionRow (Item [V ]):
34
- """Represents a UI Action Row.
32
+ """Represents a UI Action Row used in :class:`discord.ui.View` .
35
33
36
34
The items supported are as follows:
37
35
38
36
- :class:`discord.ui.Select`
39
- - :class:`discord.ui.Button` (in views)
40
- - :class:`discord.ui.InputText` (in modals)
37
+ - :class:`discord.ui.Button`
41
38
42
39
.. versionadded:: 2.7
43
40
@@ -162,7 +159,13 @@ def get_item(self, id: str | int) -> Item | None:
162
159
def add_button (
163
160
self ,
164
161
* ,
165
- accessory : Item ,
162
+ style : ButtonStyle = ButtonStyle .secondary ,
163
+ label : str | None = None ,
164
+ disabled : bool = False ,
165
+ custom_id : str | None = None ,
166
+ url : str | None = None ,
167
+ emoji : str | GuildEmoji | AppEmoji | PartialEmoji | None = None ,
168
+ sku_id : int | None = None ,
166
169
id : int | None = None ,
167
170
) -> Self :
168
171
"""Adds a :class:`Button` to the action row.
@@ -172,38 +175,96 @@ def add_button(
172
175
173
176
Parameters
174
177
----------
175
- *items: :class:`Item`
176
- The items contained in this section, up to 3.
177
- Currently only supports :class:`~discord.ui.TextDisplay`.
178
- accessory: Optional[:class:`Item`]
179
- The section's accessory. This is displayed in the top right of the section.
180
- Currently only supports :class:`~discord.ui.Button` and :class:`~discord.ui.Thumbnail`.
178
+ style: :class:`discord.ButtonStyle`
179
+ The style of the button.
180
+ custom_id: Optional[:class:`str`]
181
+ The custom ID of the button that gets received during an interaction.
182
+ If this button is for a URL, it does not have a custom ID.
183
+ url: Optional[:class:`str`]
184
+ The URL this button sends you to.
185
+ disabled: :class:`bool`
186
+ Whether the button is disabled or not.
187
+ label: Optional[:class:`str`]
188
+ The label of the button, if any. Maximum of 80 chars.
189
+ emoji: Optional[Union[:class:`.PartialEmoji`, :class:`GuildEmoji`, :class:`AppEmoji`, :class:`str`]]
190
+ The emoji of the button, if any.
191
+ sku_id: Optional[Union[:class:`int`]]
192
+ The ID of the SKU this button refers to.
181
193
id: Optional[:class:`int`]
182
- The section 's ID.
194
+ The button 's ID.
183
195
"""
184
196
185
- section = Section (* items , accessory = accessory , id = id )
197
+ button = Button (
198
+ style = style ,
199
+ label = label ,
200
+ disabled = disabled ,
201
+ custom_id = custom_id ,
202
+ url = url ,
203
+ emoji = emoji ,
204
+ sku_id = sku_id ,
205
+ id = id ,
206
+ )
186
207
187
- return self .add_item (section )
208
+ return self .add_item (button )
188
209
189
210
def add_select (
190
- self , url : str , spoiler : bool = False , id : int | None = None
211
+ self ,
212
+ select_type : ComponentType = ComponentType .string_select ,
213
+ * ,
214
+ custom_id : str | None = None ,
215
+ placeholder : str | None = None ,
216
+ min_values : int = 1 ,
217
+ max_values : int = 1 ,
218
+ options : list [SelectOption ] | None = None ,
219
+ channel_types : list [ChannelType ] | None = None ,
220
+ disabled : bool = False ,
221
+ id : int | None = None ,
191
222
) -> Self :
192
223
"""Adds a :class:`TextDisplay` to the container.
193
224
194
225
Parameters
195
226
----------
196
- url: :class:`str`
197
- The URL of this file's media. This must be an ``attachment://`` URL that references a :class:`~discord.File`.
198
- spoiler: Optional[:class:`bool`]
199
- Whether the file has the spoiler overlay. Defaults to ``False``.
200
- id: Optiona[:class:`int`]
201
- The file's ID.
227
+ select_type: :class:`discord.ComponentType`
228
+ The type of select to create. Must be one of
229
+ :attr:`discord.ComponentType.string_select`, :attr:`discord.ComponentType.user_select`,
230
+ :attr:`discord.ComponentType.role_select`, :attr:`discord.ComponentType.mentionable_select`,
231
+ or :attr:`discord.ComponentType.channel_select`.
232
+ custom_id: :class:`str`
233
+ The custom ID of the select menu that gets received during an interaction.
234
+ If not given then one is generated for you.
235
+ placeholder: Optional[:class:`str`]
236
+ The placeholder text that is shown if nothing is selected, if any.
237
+ min_values: :class:`int`
238
+ The minimum number of items that must be chosen for this select menu.
239
+ Defaults to 1 and must be between 1 and 25.
240
+ max_values: :class:`int`
241
+ The maximum number of items that must be chosen for this select menu.
242
+ Defaults to 1 and must be between 1 and 25.
243
+ options: List[:class:`discord.SelectOption`]
244
+ A list of options that can be selected in this menu.
245
+ Only valid for selects of type :attr:`discord.ComponentType.string_select`.
246
+ channel_types: List[:class:`discord.ChannelType`]
247
+ A list of channel types that can be selected in this menu.
248
+ Only valid for selects of type :attr:`discord.ComponentType.channel_select`.
249
+ disabled: :class:`bool`
250
+ Whether the select is disabled or not. Defaults to ``False``.
251
+ id: Optional[:class:`int`]
252
+ The select menu's ID.
202
253
"""
203
254
204
- f = File (url , spoiler = spoiler , id = id )
255
+ select = Select (
256
+ select_type = select_type ,
257
+ custom_id = custom_id ,
258
+ placeholder = placeholder ,
259
+ min_values = min_values ,
260
+ max_values = max_values ,
261
+ options = options or [],
262
+ channel_types = channel_types or [],
263
+ disabled = disabled ,
264
+ id = id ,
265
+ )
205
266
206
- return self .add_item (f )
267
+ return self .add_item (select )
207
268
208
269
@Item .view .setter
209
270
def view (self , value ):
@@ -236,12 +297,12 @@ def refresh_component(self, component: ActionRowComponent) -> None:
236
297
237
298
def disable_all_items (self , * , exclusions : list [Item ] | None = None ) -> Self :
238
299
"""
239
- Disables all items in this row.
300
+ Disables all items in the row.
240
301
241
302
Parameters
242
303
----------
243
304
exclusions: Optional[List[:class:`Item`]]
244
- A list of items in `self.items` to not disable from the view .
305
+ A list of items in `self.items` to not disable.
245
306
"""
246
307
for item in self .walk_items ():
247
308
if exclusions is None or item not in exclusions :
@@ -250,12 +311,12 @@ def disable_all_items(self, *, exclusions: list[Item] | None = None) -> Self:
250
311
251
312
def enable_all_items (self , * , exclusions : list [Item ] | None = None ) -> Self :
252
313
"""
253
- Enables all buttons and select menus in the container .
314
+ Enables all items in the row .
254
315
255
316
Parameters
256
317
----------
257
318
exclusions: Optional[List[:class:`Item`]]
258
- A list of items in `self.items` to not enable from the view .
319
+ A list of items in `self.items` to not enable.
259
320
"""
260
321
for item in self .walk_items ():
261
322
if hasattr (item , "disabled" ) and (
@@ -267,12 +328,12 @@ def enable_all_items(self, *, exclusions: list[Item] | None = None) -> Self:
267
328
def walk_items (self ) -> Iterator [Item ]:
268
329
yield from self .items
269
330
270
- def to_component_dict (self ) -> ContainerComponentPayload :
331
+ def to_component_dict (self ) -> ActionRowPayload :
271
332
self ._set_components (self .items )
272
333
return self ._underlying .to_dict ()
273
334
274
335
@classmethod
275
- def from_component (cls : type [C ], component : ActionRowComponent ) -> C :
336
+ def from_component (cls : type [A ], component : ActionRowComponent ) -> A :
276
337
from .view import _component_to_item
277
338
278
339
items = [
0 commit comments