Add support for components V2

Co-authored-by: Michael H <michael@michaelhall.tech>
Co-authored-by: Soheab <33902984+Soheab@users.noreply.github.com>
Co-authored-by: owocado <24418520+owocado@users.noreply.github.com>
Co-authored-by: Jay3332 <40323796+jay3332@users.noreply.github.com>
Co-authored-by: Danny <1695103+Rapptz@users.noreply.github.com>
This commit is contained in:
DA344
2025-08-14 02:37:23 +02:00
committed by GitHub
parent 6ec2e5329b
commit 50caa3c82c
33 changed files with 4214 additions and 298 deletions

View File

@ -24,6 +24,7 @@ DEALINGS IN THE SOFTWARE.
from __future__ import annotations
import copy
from typing import Any, Callable, Coroutine, Dict, Generic, Optional, TYPE_CHECKING, Tuple, Type, TypeVar
from ..interactions import Interaction
@ -36,12 +37,14 @@ __all__ = (
# fmt: on
if TYPE_CHECKING:
from typing_extensions import Self
from ..enums import ComponentType
from .view import View
from .view import BaseView
from ..components import Component
I = TypeVar('I', bound='Item[Any]')
V = TypeVar('V', bound='View', covariant=True)
V = TypeVar('V', bound='BaseView', covariant=True)
ItemCallbackType = Callable[[V, Interaction[Any], I], Coroutine[Any, Any, Any]]
@ -53,11 +56,19 @@ class Item(Generic[V]):
- :class:`discord.ui.Button`
- :class:`discord.ui.Select`
- :class:`discord.ui.TextInput`
- :class:`discord.ui.ActionRow`
- :class:`discord.ui.Container`
- :class:`discord.ui.File`
- :class:`discord.ui.MediaGallery`
- :class:`discord.ui.Section`
- :class:`discord.ui.Separator`
- :class:`discord.ui.TextDisplay`
- :class:`discord.ui.Thumbnail`
.. versionadded:: 2.0
"""
__item_repr_attributes__: Tuple[str, ...] = ('row',)
__item_repr_attributes__: Tuple[str, ...] = ('row', 'id')
def __init__(self):
self._view: Optional[V] = None
@ -70,6 +81,8 @@ class Item(Generic[V]):
# actually affect the intended purpose of this check because from_component is
# only called upon edit and we're mainly interested during initial creation time.
self._provided_custom_id: bool = False
self._id: Optional[int] = None
self._parent: Optional[Item] = None
def to_component_dict(self) -> Dict[str, Any]:
raise NotImplementedError
@ -80,6 +93,9 @@ class Item(Generic[V]):
def _refresh_state(self, interaction: Interaction, data: Dict[str, Any]) -> None:
return None
def _is_v2(self) -> bool:
return False
@classmethod
def from_component(cls: Type[I], component: Component) -> I:
return cls()
@ -92,7 +108,9 @@ class Item(Generic[V]):
return False
def is_persistent(self) -> bool:
return self._provided_custom_id
if self.is_dispatchable():
return self._provided_custom_id
return True
def __repr__(self) -> str:
attrs = ' '.join(f'{key}={getattr(self, key)!r}' for key in self.__item_repr_attributes__)
@ -104,6 +122,10 @@ class Item(Generic[V]):
@row.setter
def row(self, value: Optional[int]) -> None:
if self._is_v2():
# row is ignored on v2 components
return
if value is None:
self._row = None
elif 5 > value >= 0:
@ -117,9 +139,45 @@ class Item(Generic[V]):
@property
def view(self) -> Optional[V]:
"""Optional[:class:`View`]: The underlying view for this item."""
"""Optional[Union[:class:`View`, :class:`LayoutView`]]: The underlying view for this item."""
return self._view
@property
def id(self) -> Optional[int]:
"""Optional[:class:`int`]: The ID of this component."""
return self._id
@id.setter
def id(self, value: Optional[int]) -> None:
self._id = value
@property
def parent(self) -> Optional[Item[V]]:
"""Optional[:class:`Item`]: This item's parent. Only components that can have children
can be parents. Any item that has :class:`View` as a view will have this set to `None`
since only :class:`LayoutView` component v2 items can contain "container" like items.
.. versionadded:: 2.6
"""
return self._parent
async def _run_checks(self, interaction: Interaction[ClientT]) -> bool:
can_run = await self.interaction_check(interaction)
if can_run and self._parent:
can_run = await self._parent._run_checks(interaction)
return can_run
def _update_view(self, view) -> None:
self._view = view
def copy(self) -> Self:
return copy.deepcopy(self)
def _has_children(self) -> bool:
return False
async def callback(self, interaction: Interaction[ClientT]) -> Any:
"""|coro|