lightbulb.components¶
This package contains a framework for creating your own component and modal handlers, without having to go through the common issues when trying to do it using raw Hikari.
Component Handling¶
A Note on Select Components¶
When adding a select menu to a component menu you must store it as an instance variable. If you do not do this then getting the selected values for it will not be typed correctly.
You can get the selected values for a select menu using the
selected_values_for()
method.
Example
import lightbulb
class MyMenu(lightbulb.components.Menu):
def __init__(self) -> None:
self.select = self.add_text_select(["foo", "bar", "baz"], self.on_select)
async def on_select(self, ctx: lightbulb.components.MenuContext) -> None:
await ctx.respond(f"Selected: {ctx.selected_values_for(self.select)}")
Modal Handling¶
Creating a Modal¶
Modals are handled in a very similar way to components. Instead of subclassing Menu
, you will instead
have to subclass Modal
.
Example
import lightbulb
class MyModal(lightbulb.components.Modal):
def __init__(self) -> None:
...
Adding Components to Modals¶
Like menus, you can add components to modals using the relevant methods:
Just like menus, the modal will lay the added components out into rows automatically. You can use the same methods
next_row
, previous_row
, etc. to further customise how the layout is created.
When you add a component, the created component object is returned. You should store this within an instance variable - it will be needed later in order to get the submitted value from the modal context.
Important
Your modal subclass must implement the on_submit
method. This will be called when an interaction for
the modal is received and should perform any logic you require.
Example
import lightbulb
class MyModal(lightbulb.components.Modal):
def __init__(self) -> None:
self.text = self.add_short_text_input("Enter some text")
async def on_submit(self, ctx: lightbulb.components.ModalContext) -> None:
await ctx.respond(f"submitted: {ctx.value_for(self.text)}")
Running Modals¶
Sending a modal with a response is similar to using a menu - you should pass the modal instance to the components=
argument of respond_with_modal
of the context or interaction.
Like menus, you need the Lightbulb Client
instance in order for it to listen for the
relevant interaction. However, unlike menus, when attaching a modal to the client it will always wait for the
interaction to be received before continuing. You must also pass a timeout after which an asyncio.TimeoutError
will be raised - if you do not pass a timeout, it will default to 30 seconds.
When attaching a modal to the client, you must pass the same custom ID you used when sending the modal response, otherwise Lightbulb will not be able to resolve the correct interaction for the modal submission.
To get your Client
instance within a command, you can use dependency injection as seen in the following example.
Check the “Dependencies” guide within the by-example section of the documentation for more details about dependency
injection.
Example
import asyncio
import uuid
import lightbulb
class MyModal(lightbulb.components.Modal):
def __init__(self) -> None:
self.text = self.add_short_text_input("Enter some text")
async def on_submit(self, ctx: lightbulb.components.ModalContext) -> None:
await ctx.respond(f"submitted: {ctx.value_for(self.text)}")
class MyCommand(lightbulb.SlashCommand, name="test", description="test"):
@lightbulb.invoke
async def invoke(self, ctx: lightbulb.Context, client: lightbulb.Client) -> None:
modal = MyModal()
# Using a uuid as the custom ID for this modal means it is very unlikely that there will
# be any custom ID conflicts - if you used a set value instead then it may pick up a submission
# from a previous or future invocation of this command
await ctx.respond_with_modal("Test Modal", c_id := str(uuid.uuid4()), components=modal)
try:
await modal.attach(client, c_id)
except asyncio.TimeoutError:
await ctx.respond("Modal timed out")
Submodules:
Exported Members¶
The following members are exported to the top level of this package and so can be accessed using lightbulb.components.<member>
instead of requiring you to use the full import path.