11import contextlib
22import uuid
33from abc import abstractmethod
4- from typing import Any , Dict , Iterator , List , Optional , Union
4+ from typing import Any , Dict , Iterator , List , Optional , Union , TYPE_CHECKING
55
6+ import attrs
67import discord_typings
78
9+ import interactions .models .discord as d_models
10+ from interactions .models .discord .snowflake import Snowflake
811from interactions .client .const import ACTION_ROW_MAX_ITEMS , MISSING
912from interactions .client .mixins .serialization import DictSerializationMixin
13+ from interactions .models .discord .base import DiscordObject
1014from interactions .models .discord .emoji import PartialEmoji , process_emoji
1115from interactions .models .discord .enums import ButtonStyle , ChannelType , ComponentType
1216
17+ if TYPE_CHECKING :
18+ import interactions .models .discord
19+
1320__all__ = (
1421 "BaseComponent" ,
1522 "InteractiveComponent" ,
2633 "spread_to_rows" ,
2734 "get_components_ids" ,
2835 "TYPE_COMPONENT_MAPPING" ,
36+ "SelectDefaultValues" ,
37+ "DefaultableSelectMenu" ,
2938)
3039
3140
@@ -325,6 +334,87 @@ def to_dict(self) -> discord_typings.SelectMenuComponentData:
325334 }
326335
327336
337+ @attrs .define (eq = False , order = False , hash = False , slots = False )
338+ class SelectDefaultValues (DiscordObject ):
339+ id : Snowflake
340+ """ID of a user, role, or channel"""
341+ type : str
342+ """Type of value that id represents. Either "user", "role", or "channel"""
343+
344+ @classmethod
345+ def from_object (cls , obj : DiscordObject ) -> "SelectDefaultValues" :
346+ """Create a default value from a discord object."""
347+ match obj :
348+ case d_models .User ():
349+ return cls (id = obj .id , type = "user" )
350+ case d_models .Member ():
351+ return cls (id = obj .id , type = "user" )
352+ case d_models .BaseChannel ():
353+ return cls (id = obj .id , type = "channel" )
354+ case d_models .Role ():
355+ return cls (id = obj .id , type = "role" )
356+ case _:
357+ raise TypeError (
358+ f"Cannot convert { obj } of type { type (obj )} to a SelectDefaultValues - Expected User, Channel, Member, or Role"
359+ )
360+
361+
362+ class DefaultableSelectMenu (BaseSelectMenu ):
363+ default_values : list [
364+ Union [
365+ "interactions.models.discord.BaseUser" ,
366+ "interactions.models.discord.Role" ,
367+ "interactions.models.discord.BaseChannel" ,
368+ "interactions.models.discord.Member" ,
369+ SelectDefaultValues ,
370+ ]
371+ ] | None = None
372+
373+ def __init__ (
374+ self ,
375+ defaults : list [
376+ Union [
377+ "interactions.models.discord.BaseUser" ,
378+ "interactions.models.discord.Role" ,
379+ "interactions.models.discord.BaseChannel" ,
380+ "interactions.models.discord.Member" ,
381+ SelectDefaultValues ,
382+ ]
383+ ]
384+ | None = None ,
385+ ** kwargs ,
386+ ) -> None :
387+ super ().__init__ (** kwargs )
388+ self .default_values = defaults
389+
390+ def add_default_value (
391+ self ,
392+ value : Union [
393+ "interactions.models.discord.BaseUser" ,
394+ "interactions.models.discord.Role" ,
395+ "interactions.models.discord.BaseChannel" ,
396+ "interactions.models.discord.Member" ,
397+ SelectDefaultValues ,
398+ ],
399+ ) -> None :
400+ if self .default_values is None :
401+ self .default_values = []
402+ self .default_values .append (value )
403+
404+ def to_dict (self ) -> discord_typings .SelectMenuComponentData :
405+ data = super ().to_dict ()
406+ if self .default_values is not None :
407+ data ["default_values" ] = [ # type: ignore # waiting on discord typings to update
408+ value .to_dict ()
409+ if isinstance (value , SelectDefaultValues )
410+ else SelectDefaultValues .from_object (value ).to_dict ()
411+ for value in self .default_values
412+ ]
413+
414+ # Discord handles the type checking, no need to do it here
415+ return data
416+
417+
328418class StringSelectOption (BaseComponent ):
329419 """
330420 Represents a select option.
@@ -461,7 +551,7 @@ def to_dict(self) -> discord_typings.SelectMenuComponentData:
461551 }
462552
463553
464- class UserSelectMenu (BaseSelectMenu ):
554+ class UserSelectMenu (DefaultableSelectMenu ):
465555 """
466556 Represents a user select component.
467557
@@ -481,6 +571,16 @@ def __init__(
481571 min_values : int = 1 ,
482572 max_values : int = 1 ,
483573 custom_id : str | None = None ,
574+ default_values : list [
575+ Union [
576+ "interactions.models.discord.BaseUser" ,
577+ "interactions.models.discord.Role" ,
578+ "interactions.models.discord.BaseChannel" ,
579+ "interactions.models.discord.Member" ,
580+ SelectDefaultValues ,
581+ ],
582+ ]
583+ | None = None ,
484584 disabled : bool = False ,
485585 ) -> None :
486586 super ().__init__ (
@@ -489,12 +589,13 @@ def __init__(
489589 max_values = max_values ,
490590 custom_id = custom_id ,
491591 disabled = disabled ,
592+ defaults = default_values ,
492593 )
493594
494595 self .type : ComponentType = ComponentType .USER_SELECT
495596
496597
497- class RoleSelectMenu (BaseSelectMenu ):
598+ class RoleSelectMenu (DefaultableSelectMenu ):
498599 """
499600 Represents a user select component.
500601
@@ -515,19 +616,30 @@ def __init__(
515616 max_values : int = 1 ,
516617 custom_id : str | None = None ,
517618 disabled : bool = False ,
619+ default_values : list [
620+ Union [
621+ "interactions.models.discord.BaseUser" ,
622+ "interactions.models.discord.Role" ,
623+ "interactions.models.discord.BaseChannel" ,
624+ "interactions.models.discord.Member" ,
625+ SelectDefaultValues ,
626+ ],
627+ ]
628+ | None = None ,
518629 ) -> None :
519630 super ().__init__ (
520631 placeholder = placeholder ,
521632 min_values = min_values ,
522633 max_values = max_values ,
523634 custom_id = custom_id ,
524635 disabled = disabled ,
636+ defaults = default_values ,
525637 )
526638
527639 self .type : ComponentType = ComponentType .ROLE_SELECT
528640
529641
530- class MentionableSelectMenu (BaseSelectMenu ):
642+ class MentionableSelectMenu (DefaultableSelectMenu ):
531643 def __init__ (
532644 self ,
533645 * ,
@@ -536,19 +648,30 @@ def __init__(
536648 max_values : int = 1 ,
537649 custom_id : str | None = None ,
538650 disabled : bool = False ,
651+ default_values : list [
652+ Union [
653+ "interactions.models.discord.BaseUser" ,
654+ "interactions.models.discord.Role" ,
655+ "interactions.models.discord.BaseChannel" ,
656+ "interactions.models.discord.Member" ,
657+ SelectDefaultValues ,
658+ ],
659+ ]
660+ | None = None ,
539661 ) -> None :
540662 super ().__init__ (
541663 placeholder = placeholder ,
542664 min_values = min_values ,
543665 max_values = max_values ,
544666 custom_id = custom_id ,
545667 disabled = disabled ,
668+ defaults = default_values ,
546669 )
547670
548671 self .type : ComponentType = ComponentType .MENTIONABLE_SELECT
549672
550673
551- class ChannelSelectMenu (BaseSelectMenu ):
674+ class ChannelSelectMenu (DefaultableSelectMenu ):
552675 def __init__ (
553676 self ,
554677 * ,
@@ -558,13 +681,24 @@ def __init__(
558681 max_values : int = 1 ,
559682 custom_id : str | None = None ,
560683 disabled : bool = False ,
684+ default_values : list [
685+ Union [
686+ "interactions.models.discord.BaseUser" ,
687+ "interactions.models.discord.Role" ,
688+ "interactions.models.discord.BaseChannel" ,
689+ "interactions.models.discord.Member" ,
690+ SelectDefaultValues ,
691+ ],
692+ ]
693+ | None = None ,
561694 ) -> None :
562695 super ().__init__ (
563696 placeholder = placeholder ,
564697 min_values = min_values ,
565698 max_values = max_values ,
566699 custom_id = custom_id ,
567700 disabled = disabled ,
701+ defaults = default_values ,
568702 )
569703
570704 self .channel_types : list [ChannelType ] | None = channel_types or []
0 commit comments