# SPDX-License-Identifier: MIT from __future__ import annotations from typing import TYPE_CHECKING, ClassVar, List, Optional, Tuple, Union, cast from ..colour import Colour from ..components import Container as ContainerComponent from ..enums import ComponentType from ..utils import copy_doc from .item import UIComponent, ensure_ui_component if TYPE_CHECKING: from typing_extensions import Self from .action_row import ActionRow, ActionRowMessageComponent from .file import File from .media_gallery import MediaGallery from .section import Section from .separator import Separator from .text_display import TextDisplay ContainerChildUIComponent = Union[ ActionRow[ActionRowMessageComponent], Section, TextDisplay, MediaGallery, File, Separator, ] __all__ = ("Container",) class Container(UIComponent): """Represents a UI container. This is visually similar to :class:`.Embed`\\s, and contains other components. .. versionadded:: 2.11 Parameters ---------- *components: Union[:class:`~.ui.ActionRow`, :class:`~.ui.Section`, :class:`~.ui.TextDisplay`, :class:`~.ui.MediaGallery`, :class:`~.ui.File`, :class:`~.ui.Separator`] The components in this container. accent_colour: Optional[:class:`.Colour`] The accent colour of the container. spoiler: :class:`bool` Whether the container is marked as a spoiler. Defaults to ``False``. id: :class:`int` The numeric identifier for the component. Must be unique within the message. If set to ``0`` (the default) when sending a component, the API will assign sequential identifiers to the components in the message. Attributes ---------- children: List[Union[:class:`~.ui.ActionRow`, :class:`~.ui.Section`, :class:`~.ui.TextDisplay`, :class:`~.ui.MediaGallery`, :class:`~.ui.File`, :class:`~.ui.Separator`]] The list of child components in this container. accent_colour: Optional[:class:`.Colour`] The accent colour of the container. An alias exists under ``accent_color``. spoiler: :class:`bool` Whether the container is marked as a spoiler. """ __repr_attributes__: ClassVar[Tuple[str, ...]] = ( "children", "accent_colour", "spoiler", ) def __init__( self, *components: ContainerChildUIComponent, accent_colour: Optional[Colour] = None, spoiler: bool = False, id: int = 0, ) -> None: self._id: int = id # this list can be modified without any runtime checks later on, # just assume the user knows what they're doing at that point self.children: List[ContainerChildUIComponent] = [ ensure_ui_component(c, "components") for c in components ] self._accent_colour: Optional[Colour] = accent_colour self.spoiler: bool = spoiler # these are reimplemented here to store the value in a separate attribute, # since `Container` lazily constructs `_underlying`, unlike most components @property @copy_doc(UIComponent.id) def id(self) -> int: return self._id @id.setter def id(self, value: int) -> None: self._id = value @property def accent_colour(self) -> Optional[Colour]: return self._accent_colour @accent_colour.setter def accent_colour(self, value: Optional[Union[int, Colour]]) -> None: if isinstance(value, int): self._accent_colour = Colour(value) elif value is None or isinstance(value, Colour): self._accent_colour = value else: raise TypeError( f"Expected Colour, int, or None but received {type(value).__name__} instead." ) accent_color = accent_colour @property def _underlying(self) -> ContainerComponent: return ContainerComponent._raw_construct( type=ComponentType.container, id=self._id, children=[comp._underlying for comp in self.children], accent_colour=self._accent_colour, spoiler=self.spoiler, ) @classmethod def from_component(cls, container: ContainerComponent) -> Self: from .action_row import _to_ui_component return cls( *cast( "List[ContainerChildUIComponent]", [_to_ui_component(c) for c in container.children], ), accent_colour=container.accent_colour, spoiler=container.spoiler, id=container.id, )