loopbot-discord-sdk 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- loopbot/__init__.py +60 -0
- loopbot/bot.py +584 -0
- loopbot/builders/__init__.py +30 -0
- loopbot/builders/action_row.py +40 -0
- loopbot/builders/button.py +58 -0
- loopbot/builders/container.py +61 -0
- loopbot/builders/embed.py +95 -0
- loopbot/builders/file.py +33 -0
- loopbot/builders/media_gallery.py +36 -0
- loopbot/builders/modal.py +67 -0
- loopbot/builders/section.py +52 -0
- loopbot/builders/select_menu.py +63 -0
- loopbot/builders/separator.py +31 -0
- loopbot/builders/text_display.py +24 -0
- loopbot/client.py +805 -0
- loopbot/context/__init__.py +17 -0
- loopbot/context/base.py +263 -0
- loopbot/context/button.py +28 -0
- loopbot/context/command.py +93 -0
- loopbot/context/modal.py +46 -0
- loopbot/context/select.py +34 -0
- loopbot/types.py +76 -0
- loopbot_discord_sdk-1.0.0.dist-info/METADATA +434 -0
- loopbot_discord_sdk-1.0.0.dist-info/RECORD +26 -0
- loopbot_discord_sdk-1.0.0.dist-info/WHEEL +5 -0
- loopbot_discord_sdk-1.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Action Row Builder for grouping components
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from typing import Any, Dict, List, Union
|
|
6
|
+
|
|
7
|
+
from .button import ButtonBuilder
|
|
8
|
+
from .select_menu import SelectMenuBuilder
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class ActionRowBuilder:
|
|
12
|
+
"""Builder for Discord action rows"""
|
|
13
|
+
|
|
14
|
+
def __init__(self):
|
|
15
|
+
self._components: List[Dict[str, Any]] = []
|
|
16
|
+
|
|
17
|
+
def add_button(self, button: ButtonBuilder) -> "ActionRowBuilder":
|
|
18
|
+
"""Add a button to the row"""
|
|
19
|
+
self._components.append(button.to_dict())
|
|
20
|
+
return self
|
|
21
|
+
|
|
22
|
+
def add_select_menu(self, select: "SelectMenuBuilder") -> "ActionRowBuilder":
|
|
23
|
+
"""Add a select menu to the row"""
|
|
24
|
+
self._components.append(select.to_dict())
|
|
25
|
+
return self
|
|
26
|
+
|
|
27
|
+
def add_component(self, component: Union[Dict[str, Any], Any]) -> "ActionRowBuilder":
|
|
28
|
+
"""Add a component to the row"""
|
|
29
|
+
if hasattr(component, "to_dict"):
|
|
30
|
+
self._components.append(component.to_dict())
|
|
31
|
+
else:
|
|
32
|
+
self._components.append(component)
|
|
33
|
+
return self
|
|
34
|
+
|
|
35
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
36
|
+
"""Convert to Discord API format"""
|
|
37
|
+
return {
|
|
38
|
+
"type": 1,
|
|
39
|
+
"components": self._components,
|
|
40
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Button Builder for Discord buttons
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from enum import IntEnum
|
|
6
|
+
from typing import Any, Dict, Optional
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class ButtonStyle(IntEnum):
|
|
10
|
+
PRIMARY = 1
|
|
11
|
+
SECONDARY = 2
|
|
12
|
+
SUCCESS = 3
|
|
13
|
+
DANGER = 4
|
|
14
|
+
LINK = 5
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class ButtonBuilder:
|
|
18
|
+
"""Builder for Discord buttons"""
|
|
19
|
+
|
|
20
|
+
def __init__(self):
|
|
21
|
+
self._button: Dict[str, Any] = {"type": 2}
|
|
22
|
+
|
|
23
|
+
def set_custom_id(self, custom_id: str) -> "ButtonBuilder":
|
|
24
|
+
"""Set the button custom ID"""
|
|
25
|
+
self._button["custom_id"] = custom_id
|
|
26
|
+
return self
|
|
27
|
+
|
|
28
|
+
def set_label(self, label: str) -> "ButtonBuilder":
|
|
29
|
+
"""Set the button label"""
|
|
30
|
+
self._button["label"] = label
|
|
31
|
+
return self
|
|
32
|
+
|
|
33
|
+
def set_style(self, style: ButtonStyle) -> "ButtonBuilder":
|
|
34
|
+
"""Set the button style"""
|
|
35
|
+
self._button["style"] = int(style)
|
|
36
|
+
return self
|
|
37
|
+
|
|
38
|
+
def set_emoji(self, name: str, id: Optional[str] = None) -> "ButtonBuilder":
|
|
39
|
+
"""Set the button emoji"""
|
|
40
|
+
self._button["emoji"] = {"name": name}
|
|
41
|
+
if id:
|
|
42
|
+
self._button["emoji"]["id"] = id
|
|
43
|
+
return self
|
|
44
|
+
|
|
45
|
+
def set_url(self, url: str) -> "ButtonBuilder":
|
|
46
|
+
"""Set the button URL (for link buttons)"""
|
|
47
|
+
self._button["url"] = url
|
|
48
|
+
self._button["style"] = int(ButtonStyle.LINK)
|
|
49
|
+
return self
|
|
50
|
+
|
|
51
|
+
def set_disabled(self, disabled: bool = True) -> "ButtonBuilder":
|
|
52
|
+
"""Set whether the button is disabled"""
|
|
53
|
+
self._button["disabled"] = disabled
|
|
54
|
+
return self
|
|
55
|
+
|
|
56
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
57
|
+
"""Convert to Discord API format"""
|
|
58
|
+
return self._button
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Container Builder for Discord Components V2
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from typing import Any, Dict, List, Union
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class ContainerBuilder:
|
|
9
|
+
"""Builder for Discord Container components (requires IS_COMPONENTS_V2 flag)"""
|
|
10
|
+
|
|
11
|
+
def __init__(self):
|
|
12
|
+
self._components: List[Dict[str, Any]] = []
|
|
13
|
+
self._accent_color: int | None = None
|
|
14
|
+
self._spoiler: bool = False
|
|
15
|
+
|
|
16
|
+
def add_component(self, component: Union[Dict[str, Any], Any]) -> "ContainerBuilder":
|
|
17
|
+
"""Add a child component"""
|
|
18
|
+
if hasattr(component, "to_dict"):
|
|
19
|
+
self._components.append(component.to_dict())
|
|
20
|
+
else:
|
|
21
|
+
self._components.append(component)
|
|
22
|
+
return self
|
|
23
|
+
|
|
24
|
+
def add_text(self, content: str) -> "ContainerBuilder":
|
|
25
|
+
"""Add a text display component"""
|
|
26
|
+
self._components.append({
|
|
27
|
+
"type": 10,
|
|
28
|
+
"content": content,
|
|
29
|
+
})
|
|
30
|
+
return self
|
|
31
|
+
|
|
32
|
+
def add_separator(self, divider: bool = True, spacing: int = 1) -> "ContainerBuilder":
|
|
33
|
+
"""Add a separator component"""
|
|
34
|
+
self._components.append({
|
|
35
|
+
"type": 14,
|
|
36
|
+
"divider": divider,
|
|
37
|
+
"spacing": spacing,
|
|
38
|
+
})
|
|
39
|
+
return self
|
|
40
|
+
|
|
41
|
+
def set_accent_color(self, color: int) -> "ContainerBuilder":
|
|
42
|
+
"""Set the accent color (RGB value)"""
|
|
43
|
+
self._accent_color = color
|
|
44
|
+
return self
|
|
45
|
+
|
|
46
|
+
def set_spoiler(self, spoiler: bool = True) -> "ContainerBuilder":
|
|
47
|
+
"""Set whether container is a spoiler"""
|
|
48
|
+
self._spoiler = spoiler
|
|
49
|
+
return self
|
|
50
|
+
|
|
51
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
52
|
+
"""Convert to Discord API format"""
|
|
53
|
+
result: Dict[str, Any] = {
|
|
54
|
+
"type": 17,
|
|
55
|
+
"components": self._components,
|
|
56
|
+
}
|
|
57
|
+
if self._accent_color is not None:
|
|
58
|
+
result["accent_color"] = self._accent_color
|
|
59
|
+
if self._spoiler:
|
|
60
|
+
result["spoiler"] = self._spoiler
|
|
61
|
+
return result
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Embed Builder for Discord rich embeds
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from datetime import datetime
|
|
6
|
+
from typing import Any, Dict, List, Optional
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class EmbedBuilder:
|
|
10
|
+
"""Builder for Discord embeds"""
|
|
11
|
+
|
|
12
|
+
def __init__(self):
|
|
13
|
+
self._embed: Dict[str, Any] = {}
|
|
14
|
+
|
|
15
|
+
def set_title(self, title: str) -> "EmbedBuilder":
|
|
16
|
+
"""Set the embed title"""
|
|
17
|
+
self._embed["title"] = title
|
|
18
|
+
return self
|
|
19
|
+
|
|
20
|
+
def set_description(self, description: str) -> "EmbedBuilder":
|
|
21
|
+
"""Set the embed description"""
|
|
22
|
+
self._embed["description"] = description
|
|
23
|
+
return self
|
|
24
|
+
|
|
25
|
+
def set_url(self, url: str) -> "EmbedBuilder":
|
|
26
|
+
"""Set the embed URL"""
|
|
27
|
+
self._embed["url"] = url
|
|
28
|
+
return self
|
|
29
|
+
|
|
30
|
+
def set_color(self, color: int) -> "EmbedBuilder":
|
|
31
|
+
"""Set the embed color (RGB integer)"""
|
|
32
|
+
self._embed["color"] = color
|
|
33
|
+
return self
|
|
34
|
+
|
|
35
|
+
def set_timestamp(self, timestamp: Optional[datetime] = None) -> "EmbedBuilder":
|
|
36
|
+
"""Set the embed timestamp"""
|
|
37
|
+
if timestamp is None:
|
|
38
|
+
timestamp = datetime.utcnow()
|
|
39
|
+
self._embed["timestamp"] = timestamp.isoformat()
|
|
40
|
+
return self
|
|
41
|
+
|
|
42
|
+
def set_footer(
|
|
43
|
+
self,
|
|
44
|
+
text: str,
|
|
45
|
+
icon_url: Optional[str] = None,
|
|
46
|
+
) -> "EmbedBuilder":
|
|
47
|
+
"""Set the embed footer"""
|
|
48
|
+
self._embed["footer"] = {"text": text}
|
|
49
|
+
if icon_url:
|
|
50
|
+
self._embed["footer"]["icon_url"] = icon_url
|
|
51
|
+
return self
|
|
52
|
+
|
|
53
|
+
def set_image(self, url: str) -> "EmbedBuilder":
|
|
54
|
+
"""Set the embed image"""
|
|
55
|
+
self._embed["image"] = {"url": url}
|
|
56
|
+
return self
|
|
57
|
+
|
|
58
|
+
def set_thumbnail(self, url: str) -> "EmbedBuilder":
|
|
59
|
+
"""Set the embed thumbnail"""
|
|
60
|
+
self._embed["thumbnail"] = {"url": url}
|
|
61
|
+
return self
|
|
62
|
+
|
|
63
|
+
def set_author(
|
|
64
|
+
self,
|
|
65
|
+
name: str,
|
|
66
|
+
url: Optional[str] = None,
|
|
67
|
+
icon_url: Optional[str] = None,
|
|
68
|
+
) -> "EmbedBuilder":
|
|
69
|
+
"""Set the embed author"""
|
|
70
|
+
self._embed["author"] = {"name": name}
|
|
71
|
+
if url:
|
|
72
|
+
self._embed["author"]["url"] = url
|
|
73
|
+
if icon_url:
|
|
74
|
+
self._embed["author"]["icon_url"] = icon_url
|
|
75
|
+
return self
|
|
76
|
+
|
|
77
|
+
def add_field(
|
|
78
|
+
self,
|
|
79
|
+
name: str,
|
|
80
|
+
value: str,
|
|
81
|
+
inline: bool = False,
|
|
82
|
+
) -> "EmbedBuilder":
|
|
83
|
+
"""Add a field to the embed"""
|
|
84
|
+
if "fields" not in self._embed:
|
|
85
|
+
self._embed["fields"] = []
|
|
86
|
+
self._embed["fields"].append({
|
|
87
|
+
"name": name,
|
|
88
|
+
"value": value,
|
|
89
|
+
"inline": inline,
|
|
90
|
+
})
|
|
91
|
+
return self
|
|
92
|
+
|
|
93
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
94
|
+
"""Convert to Discord API format"""
|
|
95
|
+
return self._embed
|
loopbot/builders/file.py
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"""
|
|
2
|
+
File Builder for Discord Components V2
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from typing import Any, Dict
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class FileBuilder:
|
|
9
|
+
"""Builder for Discord File components (requires IS_COMPONENTS_V2 flag)"""
|
|
10
|
+
|
|
11
|
+
def __init__(self, url: str):
|
|
12
|
+
self._url: str = url
|
|
13
|
+
self._spoiler: bool = False
|
|
14
|
+
|
|
15
|
+
def set_url(self, url: str) -> "FileBuilder":
|
|
16
|
+
"""Set the file URL"""
|
|
17
|
+
self._url = url
|
|
18
|
+
return self
|
|
19
|
+
|
|
20
|
+
def set_spoiler(self, spoiler: bool = True) -> "FileBuilder":
|
|
21
|
+
"""Set whether file is a spoiler"""
|
|
22
|
+
self._spoiler = spoiler
|
|
23
|
+
return self
|
|
24
|
+
|
|
25
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
26
|
+
"""Convert to Discord API format"""
|
|
27
|
+
result: Dict[str, Any] = {
|
|
28
|
+
"type": 13,
|
|
29
|
+
"file": {"url": self._url},
|
|
30
|
+
}
|
|
31
|
+
if self._spoiler:
|
|
32
|
+
result["spoiler"] = self._spoiler
|
|
33
|
+
return result
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Media Gallery Builder for Discord Components V2
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from typing import Any, Dict, List, Optional
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class MediaGalleryBuilder:
|
|
9
|
+
"""Builder for Discord Media Gallery components (requires IS_COMPONENTS_V2 flag)"""
|
|
10
|
+
|
|
11
|
+
def __init__(self):
|
|
12
|
+
self._items: List[Dict[str, Any]] = []
|
|
13
|
+
|
|
14
|
+
def add_item(
|
|
15
|
+
self,
|
|
16
|
+
url: str,
|
|
17
|
+
description: Optional[str] = None,
|
|
18
|
+
spoiler: bool = False,
|
|
19
|
+
) -> "MediaGalleryBuilder":
|
|
20
|
+
"""Add a media item to the gallery"""
|
|
21
|
+
item: Dict[str, Any] = {
|
|
22
|
+
"media": {"url": url},
|
|
23
|
+
}
|
|
24
|
+
if description:
|
|
25
|
+
item["description"] = description
|
|
26
|
+
if spoiler:
|
|
27
|
+
item["spoiler"] = spoiler
|
|
28
|
+
self._items.append(item)
|
|
29
|
+
return self
|
|
30
|
+
|
|
31
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
32
|
+
"""Convert to Discord API format"""
|
|
33
|
+
return {
|
|
34
|
+
"type": 12,
|
|
35
|
+
"items": self._items,
|
|
36
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Modal Builder for Discord modals
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from typing import Any, Dict, List, Literal, Optional
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class ModalBuilder:
|
|
9
|
+
"""Builder for Discord modals"""
|
|
10
|
+
|
|
11
|
+
def __init__(self):
|
|
12
|
+
self._custom_id: str = ""
|
|
13
|
+
self._title: str = ""
|
|
14
|
+
self._components: List[Dict[str, Any]] = []
|
|
15
|
+
|
|
16
|
+
def set_custom_id(self, custom_id: str) -> "ModalBuilder":
|
|
17
|
+
"""Set the modal custom ID"""
|
|
18
|
+
self._custom_id = custom_id
|
|
19
|
+
return self
|
|
20
|
+
|
|
21
|
+
def set_title(self, title: str) -> "ModalBuilder":
|
|
22
|
+
"""Set the modal title"""
|
|
23
|
+
self._title = title
|
|
24
|
+
return self
|
|
25
|
+
|
|
26
|
+
def add_text_input(
|
|
27
|
+
self,
|
|
28
|
+
custom_id: str,
|
|
29
|
+
label: str,
|
|
30
|
+
style: Literal["short", "paragraph"] = "short",
|
|
31
|
+
required: bool = True,
|
|
32
|
+
min_length: Optional[int] = None,
|
|
33
|
+
max_length: Optional[int] = None,
|
|
34
|
+
placeholder: Optional[str] = None,
|
|
35
|
+
value: Optional[str] = None,
|
|
36
|
+
) -> "ModalBuilder":
|
|
37
|
+
"""Add a text input to the modal"""
|
|
38
|
+
input_data: Dict[str, Any] = {
|
|
39
|
+
"type": 4,
|
|
40
|
+
"custom_id": custom_id,
|
|
41
|
+
"style": 1 if style == "short" else 2,
|
|
42
|
+
"label": label,
|
|
43
|
+
"required": required,
|
|
44
|
+
}
|
|
45
|
+
if min_length is not None:
|
|
46
|
+
input_data["min_length"] = min_length
|
|
47
|
+
if max_length is not None:
|
|
48
|
+
input_data["max_length"] = max_length
|
|
49
|
+
if placeholder:
|
|
50
|
+
input_data["placeholder"] = placeholder
|
|
51
|
+
if value:
|
|
52
|
+
input_data["value"] = value
|
|
53
|
+
|
|
54
|
+
# Wrap in action row
|
|
55
|
+
self._components.append({
|
|
56
|
+
"type": 1,
|
|
57
|
+
"components": [input_data],
|
|
58
|
+
})
|
|
59
|
+
return self
|
|
60
|
+
|
|
61
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
62
|
+
"""Convert to Discord API format"""
|
|
63
|
+
return {
|
|
64
|
+
"title": self._title,
|
|
65
|
+
"custom_id": self._custom_id,
|
|
66
|
+
"components": self._components,
|
|
67
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Section Builder for Discord Components V2
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from typing import Any, Dict, List, Optional, Union
|
|
6
|
+
|
|
7
|
+
from .button import ButtonBuilder
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class SectionBuilder:
|
|
11
|
+
"""Builder for Discord Section components (requires IS_COMPONENTS_V2 flag)"""
|
|
12
|
+
|
|
13
|
+
def __init__(self):
|
|
14
|
+
self._components: List[Dict[str, Any]] = []
|
|
15
|
+
self._accessory: Dict[str, Any] | None = None
|
|
16
|
+
|
|
17
|
+
def add_text(self, content: str) -> "SectionBuilder":
|
|
18
|
+
"""Add a text display component"""
|
|
19
|
+
self._components.append({
|
|
20
|
+
"type": 10,
|
|
21
|
+
"content": content,
|
|
22
|
+
})
|
|
23
|
+
return self
|
|
24
|
+
|
|
25
|
+
def set_button_accessory(self, button: ButtonBuilder) -> "SectionBuilder":
|
|
26
|
+
"""Set a button as the accessory"""
|
|
27
|
+
self._accessory = button.to_dict()
|
|
28
|
+
return self
|
|
29
|
+
|
|
30
|
+
def set_thumbnail_accessory(
|
|
31
|
+
self,
|
|
32
|
+
url: str,
|
|
33
|
+
description: Optional[str] = None,
|
|
34
|
+
) -> "SectionBuilder":
|
|
35
|
+
"""Set a thumbnail as the accessory"""
|
|
36
|
+
self._accessory = {
|
|
37
|
+
"type": 11,
|
|
38
|
+
"media": {"url": url},
|
|
39
|
+
}
|
|
40
|
+
if description:
|
|
41
|
+
self._accessory["description"] = description
|
|
42
|
+
return self
|
|
43
|
+
|
|
44
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
45
|
+
"""Convert to Discord API format"""
|
|
46
|
+
result: Dict[str, Any] = {
|
|
47
|
+
"type": 9,
|
|
48
|
+
"components": self._components,
|
|
49
|
+
}
|
|
50
|
+
if self._accessory:
|
|
51
|
+
result["accessory"] = self._accessory
|
|
52
|
+
return result
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Select Menu Builder for Discord dropdowns
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from typing import Any, Dict, List, Optional
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class SelectMenuBuilder:
|
|
9
|
+
"""Builder for Discord select menus"""
|
|
10
|
+
|
|
11
|
+
def __init__(self):
|
|
12
|
+
self._select: Dict[str, Any] = {"type": 3, "options": []}
|
|
13
|
+
|
|
14
|
+
def set_custom_id(self, custom_id: str) -> "SelectMenuBuilder":
|
|
15
|
+
"""Set the select menu custom ID"""
|
|
16
|
+
self._select["custom_id"] = custom_id
|
|
17
|
+
return self
|
|
18
|
+
|
|
19
|
+
def set_placeholder(self, placeholder: str) -> "SelectMenuBuilder":
|
|
20
|
+
"""Set the placeholder text"""
|
|
21
|
+
self._select["placeholder"] = placeholder
|
|
22
|
+
return self
|
|
23
|
+
|
|
24
|
+
def set_min_values(self, min_values: int) -> "SelectMenuBuilder":
|
|
25
|
+
"""Set minimum values to select"""
|
|
26
|
+
self._select["min_values"] = min_values
|
|
27
|
+
return self
|
|
28
|
+
|
|
29
|
+
def set_max_values(self, max_values: int) -> "SelectMenuBuilder":
|
|
30
|
+
"""Set maximum values to select"""
|
|
31
|
+
self._select["max_values"] = max_values
|
|
32
|
+
return self
|
|
33
|
+
|
|
34
|
+
def set_disabled(self, disabled: bool = True) -> "SelectMenuBuilder":
|
|
35
|
+
"""Set whether the select is disabled"""
|
|
36
|
+
self._select["disabled"] = disabled
|
|
37
|
+
return self
|
|
38
|
+
|
|
39
|
+
def add_option(
|
|
40
|
+
self,
|
|
41
|
+
label: str,
|
|
42
|
+
value: str,
|
|
43
|
+
description: Optional[str] = None,
|
|
44
|
+
emoji: Optional[Dict[str, str]] = None,
|
|
45
|
+
default: bool = False,
|
|
46
|
+
) -> "SelectMenuBuilder":
|
|
47
|
+
"""Add an option to the select menu"""
|
|
48
|
+
option: Dict[str, Any] = {
|
|
49
|
+
"label": label,
|
|
50
|
+
"value": value,
|
|
51
|
+
}
|
|
52
|
+
if description:
|
|
53
|
+
option["description"] = description
|
|
54
|
+
if emoji:
|
|
55
|
+
option["emoji"] = emoji
|
|
56
|
+
if default:
|
|
57
|
+
option["default"] = default
|
|
58
|
+
self._select["options"].append(option)
|
|
59
|
+
return self
|
|
60
|
+
|
|
61
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
62
|
+
"""Convert to Discord API format"""
|
|
63
|
+
return self._select
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Separator Builder for Discord Components V2
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from typing import Any, Dict, Literal
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class SeparatorBuilder:
|
|
9
|
+
"""Builder for Discord Separator components (requires IS_COMPONENTS_V2 flag)"""
|
|
10
|
+
|
|
11
|
+
def __init__(self):
|
|
12
|
+
self._divider: bool = True
|
|
13
|
+
self._spacing: int = 1
|
|
14
|
+
|
|
15
|
+
def set_divider(self, divider: bool) -> "SeparatorBuilder":
|
|
16
|
+
"""Set whether to show visual divider"""
|
|
17
|
+
self._divider = divider
|
|
18
|
+
return self
|
|
19
|
+
|
|
20
|
+
def set_spacing(self, spacing: Literal[1, 2]) -> "SeparatorBuilder":
|
|
21
|
+
"""Set spacing size (1 = small, 2 = large)"""
|
|
22
|
+
self._spacing = spacing
|
|
23
|
+
return self
|
|
24
|
+
|
|
25
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
26
|
+
"""Convert to Discord API format"""
|
|
27
|
+
return {
|
|
28
|
+
"type": 14,
|
|
29
|
+
"divider": self._divider,
|
|
30
|
+
"spacing": self._spacing,
|
|
31
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Text Display Builder for Discord Components V2
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from typing import Any, Dict
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class TextDisplayBuilder:
|
|
9
|
+
"""Builder for Discord Text Display components (requires IS_COMPONENTS_V2 flag)"""
|
|
10
|
+
|
|
11
|
+
def __init__(self, content: str = ""):
|
|
12
|
+
self._content: str = content
|
|
13
|
+
|
|
14
|
+
def set_content(self, content: str) -> "TextDisplayBuilder":
|
|
15
|
+
"""Set the text content (supports markdown)"""
|
|
16
|
+
self._content = content
|
|
17
|
+
return self
|
|
18
|
+
|
|
19
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
20
|
+
"""Convert to Discord API format"""
|
|
21
|
+
return {
|
|
22
|
+
"type": 10,
|
|
23
|
+
"content": self._content,
|
|
24
|
+
}
|