DiscordPYComponents 0.2.33__tar.gz → 1.3.0__tar.gz

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.
Files changed (28) hide show
  1. discordpycomponents-1.3.0/DiscordPYComponents.egg-info/PKG-INFO +248 -0
  2. {discordpycomponents-0.2.33 → discordpycomponents-1.3.0}/DiscordPYComponents.egg-info/SOURCES.txt +2 -0
  3. discordpycomponents-1.3.0/PKG-INFO +248 -0
  4. discordpycomponents-1.3.0/README.md +236 -0
  5. discordpycomponents-1.3.0/py_components/__init__.py +94 -0
  6. discordpycomponents-1.3.0/py_components/components.py +839 -0
  7. discordpycomponents-1.3.0/py_components/enums.py +53 -0
  8. discordpycomponents-1.3.0/py_components/http.py +96 -0
  9. discordpycomponents-1.3.0/py_components/ids.py +146 -0
  10. discordpycomponents-1.3.0/py_components/modal.py +46 -0
  11. discordpycomponents-1.3.0/py_components/registry.py +31 -0
  12. discordpycomponents-1.3.0/py_components/ui.py +251 -0
  13. discordpycomponents-1.3.0/py_components/view.py +70 -0
  14. {discordpycomponents-0.2.33 → discordpycomponents-1.3.0}/pyproject.toml +7 -1
  15. discordpycomponents-0.2.33/DiscordPYComponents.egg-info/PKG-INFO +0 -68
  16. discordpycomponents-0.2.33/PKG-INFO +0 -68
  17. discordpycomponents-0.2.33/README.md +0 -60
  18. discordpycomponents-0.2.33/py_components/__init__.py +0 -4
  19. discordpycomponents-0.2.33/py_components/components.py +0 -26
  20. discordpycomponents-0.2.33/py_components/enums.py +0 -5
  21. discordpycomponents-0.2.33/py_components/http.py +0 -15
  22. discordpycomponents-0.2.33/py_components/registry.py +0 -10
  23. discordpycomponents-0.2.33/py_components/ui.py +0 -48
  24. discordpycomponents-0.2.33/py_components/view.py +0 -33
  25. {discordpycomponents-0.2.33 → discordpycomponents-1.3.0}/DiscordPYComponents.egg-info/dependency_links.txt +0 -0
  26. {discordpycomponents-0.2.33 → discordpycomponents-1.3.0}/DiscordPYComponents.egg-info/requires.txt +0 -0
  27. {discordpycomponents-0.2.33 → discordpycomponents-1.3.0}/DiscordPYComponents.egg-info/top_level.txt +0 -0
  28. {discordpycomponents-0.2.33 → discordpycomponents-1.3.0}/setup.cfg +0 -0
@@ -0,0 +1,248 @@
1
+ Metadata-Version: 2.4
2
+ Name: DiscordPYComponents
3
+ Version: 1.3.0
4
+ Summary: Discord Components V2 for discord.py
5
+ Author: 2gm49
6
+ License: MIT
7
+ Project-URL: Homepage, https://pypi.org/project/DiscordPYComponents/
8
+ Project-URL: Documentation, https://docs.discord.com/developers/components/overview
9
+ Requires-Python: >=3.10
10
+ Description-Content-Type: text/markdown
11
+ Requires-Dist: aiohttp
12
+
13
+ # DiscordPYComponents
14
+
15
+ Discord Components V2 helper for discord.py.
16
+
17
+ Needs the `IS_COMPONENTS_V2` flag (`1 << 15`). That turns off normal content/embeds — everything goes through components.
18
+
19
+ ```bash
20
+ pip install DiscordPYComponents
21
+ ```
22
+
23
+ Python 3.10+, discord.py, aiohttp.
24
+
25
+ ## Quick start
26
+
27
+ ```python
28
+ from py_components import UI, TextDisplay, Button, ButtonStyle
29
+
30
+ @bot.command()
31
+ async def menu(ctx):
32
+ ui = UI(
33
+ TextDisplay("pick one"),
34
+ Button("yes", custom_id="yes", style=ButtonStyle.SUCCESS),
35
+ Button("no", custom_id="no", style=ButtonStyle.DANGER),
36
+ )
37
+ await ui.send(ctx)
38
+ ```
39
+
40
+ ## Components
41
+
42
+ **Content**
43
+
44
+ | class | type | what |
45
+ |-------|------|------|
46
+ | `TextDisplay` / `Text` | 10 | markdown text |
47
+ | `Thumbnail` | 11 | small image (section accessory) |
48
+ | `MediaGallery` | 12 | 1-10 images |
49
+ | `File` | 13 | attachment:// file |
50
+
51
+ **Layout**
52
+
53
+ | class | type | what |
54
+ |-------|------|------|
55
+ | `ActionRow` | 1 | up to 5 buttons or one select |
56
+ | `Section` | 9 | text + button/thumbnail accessory |
57
+ | `Separator` | 14 | spacing / divider |
58
+ | `Container` | 17 | groups stuff, optional accent colour |
59
+
60
+ **Interactive**
61
+
62
+ | class | type |
63
+ |-------|------|
64
+ | `Button` | 2 |
65
+ | `StringSelect` | 3 |
66
+ | `UserSelect` | 5 |
67
+ | `RoleSelect` | 6 |
68
+ | `MentionableSelect` | 7 |
69
+ | `ChannelSelect` | 8 |
70
+
71
+ ## Buttons
72
+
73
+ ```python
74
+ ButtonStyle.PRIMARY # 1 blurple
75
+ ButtonStyle.SECONDARY # 2 grey
76
+ ButtonStyle.SUCCESS # 3 green
77
+ ButtonStyle.DANGER # 4 red
78
+ ButtonStyle.LINK # 5 needs url=
79
+ ButtonStyle.PREMIUM # 6 needs sku_id=
80
+ ```
81
+
82
+ ```python
83
+ Button("click", custom_id="x", style=ButtonStyle.PRIMARY, emoji="🔥")
84
+ Button("docs", style=ButtonStyle.LINK, url="https://discord.com/developers/docs")
85
+ ```
86
+
87
+ ## Layout example
88
+
89
+ ```python
90
+ from py_components import (
91
+ UI, Container, TextDisplay, Section, Thumbnail,
92
+ Separator, MediaGallery, Button, ButtonStyle
93
+ )
94
+
95
+ ui = UI(
96
+ Container(
97
+ TextDisplay("# status"),
98
+ Separator(),
99
+ Section(
100
+ TextDisplay("**online** — 1204 members"),
101
+ accessory=Thumbnail("https://cdn.discordapp.com/icons/.../icon.png"),
102
+ ),
103
+ MediaGallery("https://example.com/a.png", "https://example.com/b.png"),
104
+ accent_color=0x5865F2,
105
+ ),
106
+ Button("refresh", custom_id="refresh"),
107
+ )
108
+ await ui.send(ctx)
109
+ ```
110
+
111
+ Selects go in an ActionRow:
112
+
113
+ ```python
114
+ from py_components import ActionRow, StringSelect, SelectOption
115
+
116
+ ui = UI(
117
+ TextDisplay("colour?"),
118
+ ActionRow(
119
+ StringSelect(
120
+ "colour",
121
+ options=[
122
+ SelectOption("red", "red"),
123
+ SelectOption("blue", "blue"),
124
+ ],
125
+ placeholder="pick one",
126
+ )
127
+ ),
128
+ )
129
+ ```
130
+
131
+ ## Sending
132
+
133
+ ```python
134
+ await ui.send(ctx) # channel
135
+ await ui.reply(interaction) # interaction response / followup
136
+ await ui.reply(interaction, ephemeral=True)
137
+ await ui.edit(interaction) # edit original / component message
138
+ ```
139
+
140
+ Uses discord.py methods when it can, raw HTTP otherwise.
141
+
142
+ ## Component ids
143
+
144
+ Ids get assigned automatically when you build a payload. Set your own if you need stable ones:
145
+
146
+ ```python
147
+ TextDisplay("hi", id=10)
148
+ Button("x", custom_id="x", id=11)
149
+ ```
150
+
151
+ ```python
152
+ from py_components import find_by_id, replace_by_id, assign_ids
153
+
154
+ payload = ui.to_payload()
155
+ node = ui.get(10) # by id
156
+ payload = ui.replace(10, TextDisplay("updated", id=10))
157
+ ```
158
+
159
+ Handy when editing a message and only swapping one piece.
160
+
161
+ ## Modals
162
+
163
+ ```python
164
+ from py_components import (
165
+ Modal, Label, TextInput, TextInputStyle,
166
+ RadioGroup, RadioGroupOption, Checkbox, FileUpload
167
+ )
168
+
169
+ modal = Modal(
170
+ "report",
171
+ "bug report",
172
+ Label("what happened", TextInput("desc", style=TextInputStyle.PARAGRAPH)),
173
+ Label("severity", RadioGroup("sev", [
174
+ RadioGroupOption("low", "low"),
175
+ RadioGroupOption("high", "high"),
176
+ ])),
177
+ Label("i can reproduce this", Checkbox("ok")),
178
+ Label("screenshots", FileUpload("shots", min_values=0, required=False)),
179
+ )
180
+
181
+ @bot.tree.command(name="report")
182
+ async def report(interaction):
183
+ await modal.open(interaction)
184
+ ```
185
+
186
+ | class | type | notes |
187
+ |-------|------|-------|
188
+ | `Label` | 18 | wraps one control, label ≤45 |
189
+ | `TextInput` | 4 | short / paragraph |
190
+ | `FileUpload` | 19 | 0-10 files |
191
+ | `RadioGroup` | 21 | one choice, 2-10 options |
192
+ | `CheckboxGroup` | 22 | multi, 1-10 options |
193
+ | `Checkbox` | 23 | single yes/no |
194
+
195
+ Max 5 top-level components per modal.
196
+
197
+ ## Callbacks
198
+
199
+ ```python
200
+ from py_components import View, ButtonStyle
201
+
202
+ view = View()
203
+
204
+ async def on_yes(interaction):
205
+ await interaction.response.send_message("ok", ephemeral=True)
206
+
207
+ view.add_button("yes", "yes", style=ButtonStyle.SUCCESS, callback=on_yes)
208
+ payload = view.to_payload()
209
+ ```
210
+
211
+ ```python
212
+ from py_components import default_registry
213
+
214
+ @default_registry.route("yes")
215
+ async def handle_yes(interaction):
216
+ await interaction.response.send_message("ok")
217
+
218
+ await default_registry.dispatch(interaction.data["custom_id"], interaction)
219
+ ```
220
+
221
+ ## Emoji / defaults
222
+
223
+ ```python
224
+ from py_components import make_emoji, UserSelect
225
+
226
+ Button("pepe", custom_id="p", emoji=make_emoji("pepe", id=123, animated=True))
227
+ Button("ok", custom_id="ok", emoji="✅")
228
+
229
+ UserSelect(
230
+ "mods",
231
+ default_values=[{"id": "111", "type": "user"}],
232
+ min_values=1,
233
+ max_values=3,
234
+ )
235
+ ```
236
+
237
+ ## Limits (discord side)
238
+
239
+ - V2 flag can't be removed once set
240
+ - no content / embeds / stickers / poll on V2 messages
241
+ - attachments only show if referenced by a File / media component
242
+ - 40 components max per message
243
+ - buttons need an ActionRow (or section accessory)
244
+ - one select per ActionRow
245
+
246
+ ## License
247
+
248
+ MIT
@@ -9,6 +9,8 @@ py_components/__init__.py
9
9
  py_components/components.py
10
10
  py_components/enums.py
11
11
  py_components/http.py
12
+ py_components/ids.py
13
+ py_components/modal.py
12
14
  py_components/registry.py
13
15
  py_components/ui.py
14
16
  py_components/view.py
@@ -0,0 +1,248 @@
1
+ Metadata-Version: 2.4
2
+ Name: DiscordPYComponents
3
+ Version: 1.3.0
4
+ Summary: Discord Components V2 for discord.py
5
+ Author: 2gm49
6
+ License: MIT
7
+ Project-URL: Homepage, https://pypi.org/project/DiscordPYComponents/
8
+ Project-URL: Documentation, https://docs.discord.com/developers/components/overview
9
+ Requires-Python: >=3.10
10
+ Description-Content-Type: text/markdown
11
+ Requires-Dist: aiohttp
12
+
13
+ # DiscordPYComponents
14
+
15
+ Discord Components V2 helper for discord.py.
16
+
17
+ Needs the `IS_COMPONENTS_V2` flag (`1 << 15`). That turns off normal content/embeds — everything goes through components.
18
+
19
+ ```bash
20
+ pip install DiscordPYComponents
21
+ ```
22
+
23
+ Python 3.10+, discord.py, aiohttp.
24
+
25
+ ## Quick start
26
+
27
+ ```python
28
+ from py_components import UI, TextDisplay, Button, ButtonStyle
29
+
30
+ @bot.command()
31
+ async def menu(ctx):
32
+ ui = UI(
33
+ TextDisplay("pick one"),
34
+ Button("yes", custom_id="yes", style=ButtonStyle.SUCCESS),
35
+ Button("no", custom_id="no", style=ButtonStyle.DANGER),
36
+ )
37
+ await ui.send(ctx)
38
+ ```
39
+
40
+ ## Components
41
+
42
+ **Content**
43
+
44
+ | class | type | what |
45
+ |-------|------|------|
46
+ | `TextDisplay` / `Text` | 10 | markdown text |
47
+ | `Thumbnail` | 11 | small image (section accessory) |
48
+ | `MediaGallery` | 12 | 1-10 images |
49
+ | `File` | 13 | attachment:// file |
50
+
51
+ **Layout**
52
+
53
+ | class | type | what |
54
+ |-------|------|------|
55
+ | `ActionRow` | 1 | up to 5 buttons or one select |
56
+ | `Section` | 9 | text + button/thumbnail accessory |
57
+ | `Separator` | 14 | spacing / divider |
58
+ | `Container` | 17 | groups stuff, optional accent colour |
59
+
60
+ **Interactive**
61
+
62
+ | class | type |
63
+ |-------|------|
64
+ | `Button` | 2 |
65
+ | `StringSelect` | 3 |
66
+ | `UserSelect` | 5 |
67
+ | `RoleSelect` | 6 |
68
+ | `MentionableSelect` | 7 |
69
+ | `ChannelSelect` | 8 |
70
+
71
+ ## Buttons
72
+
73
+ ```python
74
+ ButtonStyle.PRIMARY # 1 blurple
75
+ ButtonStyle.SECONDARY # 2 grey
76
+ ButtonStyle.SUCCESS # 3 green
77
+ ButtonStyle.DANGER # 4 red
78
+ ButtonStyle.LINK # 5 needs url=
79
+ ButtonStyle.PREMIUM # 6 needs sku_id=
80
+ ```
81
+
82
+ ```python
83
+ Button("click", custom_id="x", style=ButtonStyle.PRIMARY, emoji="🔥")
84
+ Button("docs", style=ButtonStyle.LINK, url="https://discord.com/developers/docs")
85
+ ```
86
+
87
+ ## Layout example
88
+
89
+ ```python
90
+ from py_components import (
91
+ UI, Container, TextDisplay, Section, Thumbnail,
92
+ Separator, MediaGallery, Button, ButtonStyle
93
+ )
94
+
95
+ ui = UI(
96
+ Container(
97
+ TextDisplay("# status"),
98
+ Separator(),
99
+ Section(
100
+ TextDisplay("**online** — 1204 members"),
101
+ accessory=Thumbnail("https://cdn.discordapp.com/icons/.../icon.png"),
102
+ ),
103
+ MediaGallery("https://example.com/a.png", "https://example.com/b.png"),
104
+ accent_color=0x5865F2,
105
+ ),
106
+ Button("refresh", custom_id="refresh"),
107
+ )
108
+ await ui.send(ctx)
109
+ ```
110
+
111
+ Selects go in an ActionRow:
112
+
113
+ ```python
114
+ from py_components import ActionRow, StringSelect, SelectOption
115
+
116
+ ui = UI(
117
+ TextDisplay("colour?"),
118
+ ActionRow(
119
+ StringSelect(
120
+ "colour",
121
+ options=[
122
+ SelectOption("red", "red"),
123
+ SelectOption("blue", "blue"),
124
+ ],
125
+ placeholder="pick one",
126
+ )
127
+ ),
128
+ )
129
+ ```
130
+
131
+ ## Sending
132
+
133
+ ```python
134
+ await ui.send(ctx) # channel
135
+ await ui.reply(interaction) # interaction response / followup
136
+ await ui.reply(interaction, ephemeral=True)
137
+ await ui.edit(interaction) # edit original / component message
138
+ ```
139
+
140
+ Uses discord.py methods when it can, raw HTTP otherwise.
141
+
142
+ ## Component ids
143
+
144
+ Ids get assigned automatically when you build a payload. Set your own if you need stable ones:
145
+
146
+ ```python
147
+ TextDisplay("hi", id=10)
148
+ Button("x", custom_id="x", id=11)
149
+ ```
150
+
151
+ ```python
152
+ from py_components import find_by_id, replace_by_id, assign_ids
153
+
154
+ payload = ui.to_payload()
155
+ node = ui.get(10) # by id
156
+ payload = ui.replace(10, TextDisplay("updated", id=10))
157
+ ```
158
+
159
+ Handy when editing a message and only swapping one piece.
160
+
161
+ ## Modals
162
+
163
+ ```python
164
+ from py_components import (
165
+ Modal, Label, TextInput, TextInputStyle,
166
+ RadioGroup, RadioGroupOption, Checkbox, FileUpload
167
+ )
168
+
169
+ modal = Modal(
170
+ "report",
171
+ "bug report",
172
+ Label("what happened", TextInput("desc", style=TextInputStyle.PARAGRAPH)),
173
+ Label("severity", RadioGroup("sev", [
174
+ RadioGroupOption("low", "low"),
175
+ RadioGroupOption("high", "high"),
176
+ ])),
177
+ Label("i can reproduce this", Checkbox("ok")),
178
+ Label("screenshots", FileUpload("shots", min_values=0, required=False)),
179
+ )
180
+
181
+ @bot.tree.command(name="report")
182
+ async def report(interaction):
183
+ await modal.open(interaction)
184
+ ```
185
+
186
+ | class | type | notes |
187
+ |-------|------|-------|
188
+ | `Label` | 18 | wraps one control, label ≤45 |
189
+ | `TextInput` | 4 | short / paragraph |
190
+ | `FileUpload` | 19 | 0-10 files |
191
+ | `RadioGroup` | 21 | one choice, 2-10 options |
192
+ | `CheckboxGroup` | 22 | multi, 1-10 options |
193
+ | `Checkbox` | 23 | single yes/no |
194
+
195
+ Max 5 top-level components per modal.
196
+
197
+ ## Callbacks
198
+
199
+ ```python
200
+ from py_components import View, ButtonStyle
201
+
202
+ view = View()
203
+
204
+ async def on_yes(interaction):
205
+ await interaction.response.send_message("ok", ephemeral=True)
206
+
207
+ view.add_button("yes", "yes", style=ButtonStyle.SUCCESS, callback=on_yes)
208
+ payload = view.to_payload()
209
+ ```
210
+
211
+ ```python
212
+ from py_components import default_registry
213
+
214
+ @default_registry.route("yes")
215
+ async def handle_yes(interaction):
216
+ await interaction.response.send_message("ok")
217
+
218
+ await default_registry.dispatch(interaction.data["custom_id"], interaction)
219
+ ```
220
+
221
+ ## Emoji / defaults
222
+
223
+ ```python
224
+ from py_components import make_emoji, UserSelect
225
+
226
+ Button("pepe", custom_id="p", emoji=make_emoji("pepe", id=123, animated=True))
227
+ Button("ok", custom_id="ok", emoji="✅")
228
+
229
+ UserSelect(
230
+ "mods",
231
+ default_values=[{"id": "111", "type": "user"}],
232
+ min_values=1,
233
+ max_values=3,
234
+ )
235
+ ```
236
+
237
+ ## Limits (discord side)
238
+
239
+ - V2 flag can't be removed once set
240
+ - no content / embeds / stickers / poll on V2 messages
241
+ - attachments only show if referenced by a File / media component
242
+ - 40 components max per message
243
+ - buttons need an ActionRow (or section accessory)
244
+ - one select per ActionRow
245
+
246
+ ## License
247
+
248
+ MIT