Source code for discohook.modal

import asyncio
from typing import Any, Dict, List, Optional, Callable, TYPE_CHECKING

from .abc import Component
from .enums import ComponentType, TextInputFieldLength

if TYPE_CHECKING:
    from .interaction import Interaction


class TextInput:
    """
    Represents a text input field in a modal.

    Parameters
    ----------
    label: :class:`str`
        The label of the text input field.
    field_id: :class:`str`
        A unique id of the text input field. Must be valid python identifier.
    required: :class:`bool`
        Whether the text input field is required.
    hint: :class:`str`
        The hint of the text input field.
    default_text: :class:`str`
        The default text of the text input field.
    min_length: :class:`int`
        The minimum length of the text input field.
    max_length: :class:`int`
        The maximum length of the text input field.
    style: :class:`TextInputFieldLength`
        The style of the text input field.
    """

    def __init__(
        self,
        label: str,
        field_id: str,
        *,
        required: bool = False,
        hint: Optional[str] = None,
        default_text: Optional[str] = None,
        min_length: int = 0,
        max_length: int = 4000,
        style: TextInputFieldLength = TextInputFieldLength.short,
    ):
        self.label = label
        assert field_id.isidentifier(), "field_id must be a valid python identifier"
        self.field_id = field_id
        self.required = required
        self.hint = hint
        self.default_text = default_text
        self.min_length = min_length
        self.max_length = max_length
        self.style = style

    def to_dict(self):
        return {
            "type": ComponentType.action_row.value,
            "components": [
                {
                    "type": 4,
                    "label": self.label,
                    "style": self.style.value,
                    "value": self.default_text,
                    "custom_id": self.field_id,
                    "min_length": self.min_length,
                    "max_length": self.max_length,
                    "placeholder": self.hint or "",
                    "required": self.required,
                }
            ],
        }





def new(
    title: str,
    *,
    fields: List[TextInput],
    custom_id: Optional[str] = None,
):
    """
    A decorator that creates a modal and registers a callback.

    Parameters
    ----------
    title: str
        The title of the modal.
    fields: List[TextInput]
        The fields to be added to the modal.
    custom_id: Optional[str]
        The custom id of the modal. If not provided, it will be generated automatically.

    Returns
    -------
    :class:`Modal`

    Raises
    ------
    TypeError
        If the callback is not a coroutine.
    """

    def decorator(coro: Callable[["Interaction", Any], Any]):
        if not asyncio.iscoroutinefunction(coro):
            raise TypeError("Callback must be a coroutine.")
        self = Modal(title, custom_id=custom_id)
        for field in fields:
            self.rows.append(field.to_dict())
        self.callback = coro
        return self

    return decorator