Skip to content

Commit 785a357

Browse files
authored
TextDisplay and all Selects in modals
1 parent efe8fe6 commit 785a357

File tree

1 file changed

+30
-33
lines changed

1 file changed

+30
-33
lines changed

discord/ui/modal.py

Lines changed: 30 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,14 @@
66
import time
77
from functools import partial
88
from itertools import groupby
9-
from typing import TYPE_CHECKING, Any, Callable
9+
from typing import TYPE_CHECKING, Any, Callable, TypeVar
1010

1111
from ..enums import ComponentType
1212
from ..utils import find
1313
from .input_text import InputText
14+
from .item import Item
1415
from .select import Select
16+
from .text_display import TextDisplay
1517

1618
__all__ = (
1719
"Modal",
@@ -25,6 +27,8 @@
2527
from ..interactions import Interaction
2628
from ..state import ConnectionState
2729

30+
M = TypeVar("M", bound="Modal", covariant=True)
31+
2832

2933
class Modal:
3034
"""Represents a UI Modal dialog.
@@ -35,12 +39,12 @@ class Modal:
3539
3640
.. versionchanged:: 2.7
3741
38-
:attr:`discord.ComponentType.string_select` can now be used in modals.
42+
:class:`discord.ui.Select` and :class:`discord.ui.TextDisplay` can now be used in modals.
3943
4044
Parameters
4145
----------
42-
children: Union[:class:`InputText`, :class:`Select`]
43-
The initial InputText or Select components that are displayed in the modal dialog.
46+
children: Union[:class:`InputText`, :class:`Select`, :class:`TextDisplay`]
47+
The initial InputText, Select, or TextDisplay components that are displayed in the modal dialog.
4448
title: :class:`str`
4549
The title of the modal dialog.
4650
Must be 45 characters or fewer.
@@ -60,7 +64,7 @@ class Modal:
6064

6165
def __init__(
6266
self,
63-
*children: InputText | Select,
67+
*children: Item[M],
6468
title: str,
6569
custom_id: str | None = None,
6670
timeout: float | None = None,
@@ -74,7 +78,7 @@ def __init__(
7478
if len(title) > 45:
7579
raise ValueError("title must be 45 characters or fewer")
7680
self._title = title
77-
self._children: list[InputText | Select] = list(children)
81+
self._children: list[Item[M]] = list(children)
7882
self._weights = _ModalWeights(self._children)
7983
loop = asyncio.get_running_loop()
8084
self._stopped: asyncio.Future[bool] = loop.create_future()
@@ -145,23 +149,18 @@ def title(self, value: str):
145149
self._title = value
146150

147151
@property
148-
def children(self) -> list[InputText | Select]:
152+
def children(self) -> list[Item[M]]:
149153
"""The child components associated with the modal dialog."""
150154
return self._children
151155

152156
@children.setter
153-
def children(self, value: list[InputText | Select]):
157+
def children(self, value: list[Item[M]]):
154158
for item in value:
155-
if not isinstance(item, (InputText, Select)):
159+
if not isinstance(item, (InputText, Select, TextDisplay)):
156160
raise TypeError(
157-
"all Modal children must be InputText or Select, not"
161+
"all Modal children must be InputText, Select, or TextDisplay, not"
158162
f" {item.__class__.__name__}"
159163
)
160-
elif (
161-
isinstance(item, Select)
162-
and item.type is not ComponentType.string_select
163-
):
164-
raise TypeError("only string selects may be added to modals")
165164
self._weights = _ModalWeights(self._children)
166165
self._children = value
167166

@@ -194,7 +193,7 @@ async def callback(self, interaction: Interaction):
194193
self.stop()
195194

196195
def to_components(self) -> list[dict[str, Any]]:
197-
def key(item: InputText | Select) -> int:
196+
def key(item: Item[M]) -> int:
198197
return item._rendered_row or 0
199198

200199
children = sorted(self._children, key=key)
@@ -231,35 +230,33 @@ def key(item: InputText | Select) -> int:
231230

232231
return components
233232

234-
def add_item(self, item: InputText | Select) -> Self:
235-
"""Adds an InputText or Select component to the modal dialog.
233+
def add_item(self, item: Item[M]) -> Self:
234+
"""Adds a component to the modal dialog.
236235
237236
Parameters
238237
----------
239-
item: Union[:class:`InputText`, :class:`Select`]
238+
item: Union[:class:`Item`]
240239
The item to add to the modal dialog
241240
"""
242241

243242
if len(self._children) > 5:
244243
raise ValueError("You can only have up to 5 items in a modal dialog.")
245244

246-
if not isinstance(item, (InputText, Select)):
247-
raise TypeError(f"expected InputText or Select, not {item.__class__!r}")
248-
if isinstance(item, Select) and item.type is not ComponentType.string_select:
249-
raise TypeError("only string selects may be added to modals")
250-
if not item.label:
251-
raise ValueError("Item must have a label set")
245+
if not isinstance(item, (InputText, Select, TextDisplay)):
246+
raise TypeError(f"expected InputText, Select, or TextDisplay, not {item.__class__!r}")
247+
if isinstance(item, (InputText, Select)) and not item.label:
248+
raise ValueError("InputTexts and Selects must have a label set")
252249

253250
self._weights.add_item(item)
254251
self._children.append(item)
255252
return self
256253

257-
def remove_item(self, item: InputText | Select) -> Self:
258-
"""Removes an InputText or Select component from the modal dialog.
254+
def remove_item(self, item: Item[M]) -> Self:
255+
"""Removes a component from the modal dialog.
259256
260257
Parameters
261258
----------
262-
item: Union[:class:`InputText`, :class:`Select`]
259+
item: Union[:class:`Item`]
263260
The item to remove from the modal dialog.
264261
"""
265262
try:
@@ -268,7 +265,7 @@ def remove_item(self, item: InputText | Select) -> Self:
268265
pass
269266
return self
270267

271-
def get_item(self, id: str | int) -> Select | InputText | None:
268+
def get_item(self, id: str | int) -> Item[M] | None:
272269
"""Gets an item from the modal. Roughly equal to `utils.get(modal.children, ...)`.
273270
If an :class:`int` is provided, the item will be retrieved by ``id``, otherwise by ``custom_id``.
274271
@@ -333,7 +330,7 @@ async def on_timeout(self) -> None:
333330
class _ModalWeights:
334331
__slots__ = ("weights",)
335332

336-
def __init__(self, children: list[InputText | Select]):
333+
def __init__(self, children: list[Item[M]]):
337334
self.weights: list[int] = [0, 0, 0, 0, 0]
338335

339336
key = lambda i: sys.maxsize if i.row is None else i.row
@@ -342,14 +339,14 @@ def __init__(self, children: list[InputText | Select]):
342339
for item in group:
343340
self.add_item(item)
344341

345-
def find_open_space(self, item: InputText | Select) -> int:
342+
def find_open_space(self, item: Item[M]) -> int:
346343
for index, weight in enumerate(self.weights):
347344
if weight + item.width <= 5:
348345
return index
349346

350347
raise ValueError("could not find open space for item")
351348

352-
def add_item(self, item: InputText | Select) -> None:
349+
def add_item(self, item: Item[M]) -> None:
353350
if item.row is not None:
354351
total = self.weights[item.row] + item.width
355352
if total > 5:
@@ -363,7 +360,7 @@ def add_item(self, item: InputText | Select) -> None:
363360
self.weights[index] += item.width
364361
item._rendered_row = index
365362

366-
def remove_item(self, item: InputText | Select) -> None:
363+
def remove_item(self, item: Item[M]) -> None:
367364
if item._rendered_row is not None:
368365
self.weights[item._rendered_row] -= item.width
369366
item._rendered_row = None

0 commit comments

Comments
 (0)