4949 ComponentType as ComponentTypeLiteral ,
5050 ContainerComponent as ContainerComponentPayload ,
5151 FileComponent as FileComponentPayload ,
52+ LabelComponent as LabelComponentPayload ,
5253 MediaGalleryComponent as MediaGalleryComponentPayload ,
5354 MediaGalleryItem as MediaGalleryItemPayload ,
5455 MentionableSelectMenu as MentionableSelectMenuPayload ,
8990 "FileComponent" ,
9091 "Separator" ,
9192 "Container" ,
93+ "Label" ,
9294)
9395
9496# miscellaneous components-related type aliases
135137 "Separator" ,
136138]
137139
140+ # valid `Label.component` types
141+ LabelChildComponent = Union [
142+ "TextInput" ,
143+ "StringSelectMenu" ,
144+ ]
145+
138146# valid `Message.components` item types (v1/v2)
139147MessageTopLevelComponentV1 : TypeAlias = "ActionRow[ActionRowMessageComponent]"
140148MessageTopLevelComponentV2 = Union [
@@ -164,6 +172,7 @@ class Component:
164172 - :class:`FileComponent`
165173 - :class:`Separator`
166174 - :class:`Container`
175+ - :class:`Label`
167176
168177 This class is abstract and cannot be instantiated.
169178
@@ -386,6 +395,11 @@ class BaseSelectMenu(Component):
386395 Only available for auto-populated select menus.
387396
388397 .. versionadded:: 2.10
398+ required: :class:`bool`
399+ Whether the select menu is required. Only applies to components in modals.
400+ Defaults to ``True``.
401+
402+ .. versionadded:: 2.11
389403 id: :class:`int`
390404 The numeric identifier for the component.
391405 This is always present in components received from the API,
@@ -401,6 +415,7 @@ class BaseSelectMenu(Component):
401415 "max_values" ,
402416 "disabled" ,
403417 "default_values" ,
418+ "required" ,
404419 )
405420
406421 # FIXME: this isn't pretty; we should decouple __repr__ from slots
@@ -424,6 +439,7 @@ def __init__(self, data: AnySelectMenuPayload) -> None:
424439 self .default_values : List [SelectDefaultValue ] = [
425440 SelectDefaultValue ._from_dict (d ) for d in (data .get ("default_values" ) or [])
426441 ]
442+ self .required : bool = data .get ("required" , True )
427443
428444 def to_dict (self ) -> BaseSelectMenuPayload :
429445 payload : BaseSelectMenuPayload = {
@@ -433,6 +449,7 @@ def to_dict(self) -> BaseSelectMenuPayload:
433449 "min_values" : self .min_values ,
434450 "max_values" : self .max_values ,
435451 "disabled" : self .disabled ,
452+ "required" : self .required ,
436453 }
437454
438455 if self .placeholder :
@@ -472,6 +489,11 @@ class StringSelectMenu(BaseSelectMenu):
472489 Whether the select menu is disabled or not.
473490 options: List[:class:`SelectOption`]
474491 A list of options that can be selected in this select menu.
492+ required: :class:`bool`
493+ Whether the select menu is required. Only applies to components in modals.
494+ Defaults to ``True``.
495+
496+ .. versionadded:: 2.11
475497 id: :class:`int`
476498 The numeric identifier for the component.
477499 This is always present in components received from the API,
@@ -531,6 +553,11 @@ class UserSelectMenu(BaseSelectMenu):
531553 If set, the number of items must be within the bounds set by ``min_values`` and ``max_values``.
532554
533555 .. versionadded:: 2.10
556+ required: :class:`bool`
557+ Whether the select menu is required. Only applies to components in modals.
558+ Defaults to ``True``.
559+
560+ .. versionadded:: 2.11
534561 id: :class:`int`
535562 The numeric identifier for the component.
536563 This is always present in components received from the API,
@@ -577,6 +604,11 @@ class RoleSelectMenu(BaseSelectMenu):
577604 If set, the number of items must be within the bounds set by ``min_values`` and ``max_values``.
578605
579606 .. versionadded:: 2.10
607+ required: :class:`bool`
608+ Whether the select menu is required. Only applies to components in modals.
609+ Defaults to ``True``.
610+
611+ .. versionadded:: 2.11
580612 id: :class:`int`
581613 The numeric identifier for the component.
582614 This is always present in components received from the API,
@@ -623,6 +655,11 @@ class MentionableSelectMenu(BaseSelectMenu):
623655 If set, the number of items must be within the bounds set by ``min_values`` and ``max_values``.
624656
625657 .. versionadded:: 2.10
658+ required: :class:`bool`
659+ Whether the select menu is required. Only applies to components in modals.
660+ Defaults to ``True``.
661+
662+ .. versionadded:: 2.11
626663 id: :class:`int`
627664 The numeric identifier for the component.
628665 This is always present in components received from the API,
@@ -672,6 +709,11 @@ class ChannelSelectMenu(BaseSelectMenu):
672709 If set, the number of items must be within the bounds set by ``min_values`` and ``max_values``.
673710
674711 .. versionadded:: 2.10
712+ required: :class:`bool`
713+ Whether the select menu is required. Only applies to components in modals.
714+ Defaults to ``True``.
715+
716+ .. versionadded:: 2.11
675717 id: :class:`int`
676718 The numeric identifier for the component.
677719 This is always present in components received from the API,
@@ -861,6 +903,10 @@ class TextInput(Component):
861903 The style of the text input.
862904 label: Optional[:class:`str`]
863905 The label of the text input.
906+
907+ .. deprecated:: 2.11
908+ Deprecated in favor of :class:`Label`.
909+
864910 custom_id: :class:`str`
865911 The ID of the text input that gets received during an interaction.
866912 placeholder: Optional[:class:`str`]
@@ -902,7 +948,7 @@ def __init__(self, data: TextInputPayload) -> None:
902948 self .style : TextInputStyle = try_enum (
903949 TextInputStyle , data .get ("style" , TextInputStyle .short .value )
904950 )
905- self .label : Optional [str ] = data .get ("label" )
951+ self .label : Optional [str ] = data .get ("label" ) # deprecated
906952 self .placeholder : Optional [str ] = data .get ("placeholder" )
907953 self .value : Optional [str ] = data .get ("value" )
908954 self .required : bool = data .get ("required" , True )
@@ -914,7 +960,7 @@ def to_dict(self) -> TextInputPayload:
914960 "type" : self .type .value ,
915961 "id" : self .id ,
916962 "style" : self .style .value ,
917- "label" : cast ( "str" , self .label ) ,
963+ "label" : self .label ,
918964 "custom_id" : self .custom_id ,
919965 "required" : self .required ,
920966 }
@@ -1420,6 +1466,65 @@ def accent_color(self) -> Optional[Colour]:
14201466 return self .accent_colour
14211467
14221468
1469+ class Label (Component ):
1470+ """Represents a label from the Discord Bot UI Kit.
1471+
1472+ This wraps other components with a label and an optional description,
1473+ and can only be used in modals.
1474+
1475+ .. versionadded:: 2.11
1476+
1477+ .. note::
1478+
1479+ The user constructible and usable type to create a label is
1480+ :class:`disnake.ui.Label`, not this one.
1481+
1482+ Attributes
1483+ ----------
1484+ text: :class:`str`
1485+ The label text.
1486+ description: Optional[:class:`str`]
1487+ The description text for the label.
1488+ component: Union[:class:`TextInput`, :class:`StringSelectMenu`]
1489+ The component within the label.
1490+ id: :class:`int`
1491+ The numeric identifier for the component.
1492+ This is always present in components received from the API,
1493+ and unique within a message.
1494+ """
1495+
1496+ __slots__ : Tuple [str , ...] = (
1497+ "text" ,
1498+ "description" ,
1499+ "component" ,
1500+ )
1501+
1502+ __repr_info__ : ClassVar [Tuple [str , ...]] = __slots__
1503+
1504+ def __init__ (self , data : LabelComponentPayload ) -> None :
1505+ self .type : Literal [ComponentType .label ] = ComponentType .label
1506+ self .id = data .get ("id" , 0 )
1507+
1508+ self .text : str = data ["label" ]
1509+ self .description : Optional [str ] = data .get ("description" )
1510+
1511+ component = _component_factory (data ["component" ])
1512+ self .component : LabelChildComponent = component # type: ignore
1513+
1514+ def to_dict (self ) -> LabelComponentPayload :
1515+ payload : LabelComponentPayload = {
1516+ "type" : self .type .value ,
1517+ "id" : self .id ,
1518+ "label" : self .text ,
1519+ "component" : self .component .to_dict (),
1520+ }
1521+
1522+ if self .description is not None :
1523+ payload ["description" ] = self .description
1524+
1525+ return payload
1526+
1527+
14231528# types of components that are allowed in a message's action rows;
14241529# see also `ActionRowMessageComponent` type alias
14251530VALID_ACTION_ROW_MESSAGE_COMPONENT_TYPES : Final = (
@@ -1467,6 +1572,7 @@ def handle_media_item_input(value: MediaItemInput) -> UnfurledMediaItem:
14671572 ComponentType .file .value : FileComponent ,
14681573 ComponentType .separator .value : Separator ,
14691574 ComponentType .container .value : Container ,
1575+ ComponentType .label .value : Label ,
14701576}
14711577
14721578
0 commit comments