Navigators#
A common usecase for buttons is creating paginated button-menus. In miru, these are called
navigators, and such functionality is provided by the extension miru.ext.nav
.
Note
miru.ext.nav
is included with your installation, but is not imported implicitly,
thus you have to explicitly import the module.
The base of any navigator is the NavigatorView
, a specialized view
designed for creating navigators. To get started, it's as easy as creating a new instance of it,
turning it into a builder, and sending it to a channel or interaction.
import hikari
import miru
# Import the navigation module
from miru.ext import nav
bot = hikari.GatewayBot("...")
client = miru.Client(bot)
@bot.listen()
async def navigator(event: hikari.MessageCreateEvent) -> None:
# Do not process messages from bots or webhooks
if not event.is_human:
return
me = bot.get_me()
# If the bot is mentioned
if me.id in event.message.user_mentions_ids:
embed = hikari.Embed(
title="I'm the second page!",
description="Also an embed!"
)
# A Page object can be used to further customize the page payload
page = nav.Page(
content="I'm the last page!",
embed=hikari.Embed(title="I also have an embed!")
)
# The list of pages this navigator should paginate through
# This should be a list that contains
# 'str', 'hikari.Embed', or 'nav.Page' objects.
pages = ["I'm the first page!", embed, page]
# Define our navigator and pass in our list of pages
navigator = nav.NavigatorView(pages=pages)
builder = await navigator.build_response_async(client)
await builder.send_to_channel(event.channel_id)
client.start_view(navigator)
bot.run()
async def handle_command(interaction: hikari.CommandInteraction):
embed = hikari.Embed(
title="I'm the second page!",
description="Also an embed!"
)
# A Page object can be used to further customize the page payload
page = nav.Page(
content="I'm the last page!",
embed=hikari.Embed(title="I also have an embed!")
)
# The list of pages this navigator should paginate through
# This should be a list that contains
# 'str', 'hikari.Embed', or 'nav.Page' objects.
pages = ["I'm the first page!", embed, page]
# Define our navigator and pass in our list of pages
navigator = nav.NavigatorView(pages=pages)
builder = await navigator.build_response_async(client)
yield builder
client.start_view(navigator)
async def create_commands(bot: hikari.RESTBot) -> None:
application = await bot.rest.fetch_application()
await bot.rest.set_application_commands(
application=application.id,
commands=[
bot.rest.slash_command_builder("test", "My first test command!"),
],
)
bot.add_startup_callback(create_commands)
bot.set_listener(hikari.CommandInteraction, handle_command)
bot.run()
import arc
import hikari
import miru
# Import the navigation module
from miru.ext import nav
bot = hikari.GatewayBot("TOKEN")
arc_client = arc.GatewayClient(bot)
client = miru.Client.from_arc(arc_client)
@arc_client.include
@arc.slash_command("name", "description")
async def my_command(ctx: arc.GatewayContext) -> None:
embed = hikari.Embed(
title="I'm the second page!",
description="Also an embed!"
)
# A Page object can be used to further customize the page payload
page = nav.Page(
content="I'm the last page!",
embed=hikari.Embed(title="I also have an embed!")
)
# The list of pages this navigator should paginate through
# This should be a list that contains
# 'str', 'hikari.Embed', or 'nav.Page' objects.
pages = ["I'm the first page!", embed, page]
# Define our navigator and pass in our list of pages
navigator = nav.NavigatorView(pages=pages)
builder = await navigator.build_response_async(client)
await ctx.respond_with_builder(builder)
client.start_view(navigator)
bot.run()
import arc
import hikari
import miru
# Import the navigation module
from miru.ext import nav
bot = hikari.RESTBot("TOKEN")
arc_client = arc.RESTClient(bot)
client = miru.Client.from_arc(arc_client)
@arc_client.include
@arc.slash_command("name", "description")
async def my_command(ctx: arc.RESTContext) -> None:
embed = hikari.Embed(
title="I'm the second page!",
description="Also an embed!"
)
# A Page object can be used to further customize the page payload
page = nav.Page(
content="I'm the last page!",
embed=hikari.Embed(title="I also have an embed!")
)
# The list of pages this navigator should paginate through
# This should be a list that contains
# 'str', 'hikari.Embed', or 'nav.Page' objects.
pages = ["I'm the first page!", embed, page]
# Define our navigator and pass in our list of pages
navigator = nav.NavigatorView(pages=pages)
builder = await navigator.build_response_async(client)
await ctx.respond_with_builder(builder)
client.start_view(navigator)
bot.run()
import crescent
import hikari
import miru
bot = hikari.GatewayBot("TOKEN")
client = miru.Client(bot)
crescent_client = crescent.Client(bot)
@crescent_client.include
@crescent.command("name", "description")
class SomeSlashCommand:
async def callback(self, ctx: crescent.Context) -> None:
embed = hikari.Embed(
title="I'm the second page!",
description="Also an embed!"
)
# A Page object can be used to further customize the page payload
page = nav.Page(
content="I'm the last page!",
embed=hikari.Embed(title="I also have an embed!")
)
# The list of pages this navigator should paginate through
# This should be a list that contains
# 'str', 'hikari.Embed', or 'nav.Page' objects.
pages = ["I'm the first page!", embed, page]
# Define our navigator and pass in our list of pages
navigator = nav.NavigatorView(pages=pages)
builder = await navigator.build_response_async(client)
await ctx.respond_with_builder(builder)
client.start_view(navigator)
bot.run()
import crescent
import hikari
import miru
bot = hikari.RESTBot("TOKEN")
client = miru.Client(bot)
crescent_client = crescent.Client(bot)
@crescent_client.include
@crescent.command("name", "description")
class SomeSlashCommand:
async def callback(self, ctx: crescent.Context) -> None:
embed = hikari.Embed(
title="I'm the second page!",
description="Also an embed!"
)
# A Page object can be used to further customize the page payload
page = nav.Page(
content="I'm the last page!",
embed=hikari.Embed(title="I also have an embed!")
)
# The list of pages this navigator should paginate through
# This should be a list that contains
# 'str', 'hikari.Embed', or 'nav.Page' objects.
pages = ["I'm the first page!", embed, page]
# Define our navigator and pass in our list of pages
navigator = nav.NavigatorView(pages=pages)
builder = await navigator.build_response_async(client)
await ctx.respond_with_builder(builder)
client.start_view(navigator)
bot.run()
import hikari
import lightbulb
import miru
# Import the navigation module
from miru.ext import nav
bot = lightbulb.BotApp("TOKEN")
client = miru.Client(bot)
@bot.command
@lightbulb.command("name", "description", auto_defer=False)
@lightbulb.implements(lightbulb.SlashCommand)
async def my_command(ctx: lightbulb.SlashContext) -> None:
embed = hikari.Embed(
title="I'm the second page!",
description="Also an embed!"
)
# A Page object can be used to further customize the page payload
page = nav.Page(
content="I'm the last page!",
embed=hikari.Embed(title="I also have an embed!")
)
# The list of pages this navigator should paginate through
# This should be a list that contains
# 'str', 'hikari.Embed', or 'nav.Page' objects.
pages = ["I'm the first page!", embed, page]
# Define our navigator and pass in our list of pages
navigator = nav.NavigatorView(pages=pages)
builder = await navigator.build_response_async(client)
await builder.create_initial_response(ctx.interaction)
# Or in a prefix command:
# await builder.send_to_channel(ctx.channel_id)
client.start_view(navigator)
bot.run()
import hikari
import miru
import tanjun
# Import the navigation module
from miru.ext import nav
bot = hikari.GatewayBot("TOKEN")
tanjun_client = tanjun.Client.from_gateway_bot(bot)
client = miru.Client.from_tanjun(tanjun_client)
@tanjun.as_slash_command("name", "description")
async def some_slash_command(ctx: tanjun.abc.SlashContext) -> None:
embed = hikari.Embed(
title="I'm the second page!",
description="Also an embed!"
)
# A Page object can be used to further customize the page payload
page = nav.Page(
content="I'm the last page!",
embed=hikari.Embed(title="I also have an embed!")
)
# The list of pages this navigator should paginate through
# This should be a list that contains
# 'str', 'hikari.Embed', or 'nav.Page' objects.
pages = ["I'm the first page!", embed, page]
# Define our navigator and pass in our list of pages
navigator = nav.NavigatorView(pages=pages)
builder = await navigator.build_response_async(client)
# the builder has specific adapters for tanjun
await builder.respond_with_tanjun(ctx)
client.start_view(navigator)
bot.run()
import hikari
import miru
import tanjun
# Import the navigation module
from miru.ext import nav
bot = hikari.RESTBot("TOKEN")
tanjun_client = tanjun.Client.from_rest_bot(bot)
client = miru.Client.from_tanjun(tanjun_client)
@tanjun.as_slash_command("name", "description")
async def some_slash_command(ctx: tanjun.abc.SlashContext) -> None:
embed = hikari.Embed(
title="I'm the second page!",
description="Also an embed!"
)
# A Page object can be used to further customize the page payload
page = nav.Page(
content="I'm the last page!",
embed=hikari.Embed(title="I also have an embed!")
)
# The list of pages this navigator should paginate through
# This should be a list that contains
# 'str', 'hikari.Embed', or 'nav.Page' objects.
pages = ["I'm the first page!", embed, page]
# Define our navigator and pass in our list of pages
navigator = nav.NavigatorView(pages=pages)
builder = await navigator.build_response_async(client)
# the builder has specific adapters for tanjun
await builder.respond_with_tanjun(ctx)
client.start_view(navigator)
bot.run()
Tip
If you want to send a navigator in response to a miru
item being interacted with, you may use Context.respond_with_builder()
.
Customizing Navigation Buttons#
If you would like to customize the items used by the navigator, you can pass buttons & selects via the items=
keyword-only
argument. This should be a sequence of NavItem
(for a full list, see here).
There are also some built-in navigation buttons, these are:
FirstButton
- Jump to first pagePrevButton
- Jump to previous pageNextButton
- Jump to next pageLastButton
- Jump to last pageStopButton
- Stop the navigation sessionIndicatorButton
- Show the current page and max pages
You may use any mix of the built-in and custom navigation buttons in your navigator views.
Let's define a custom navigation button:
class MyIndicatorButton(nav.NavButton):
def __init__(self):
super().__init__(label="Page: 1", row=1)
async def callback(self, ctx: miru.ViewContext) -> None:
await ctx.respond("You clicked me!", flags=hikari.MessageFlag.EPHEMERAL)
async def before_page_change(self) -> None:
# This function is called before the new page is sent by the navigator
self.label = f"Page: {self.view.current_page+1}"
Then we can add it to our Navigator before sending:
embed = hikari.Embed(title="I'm the second page!", description="Also an embed!")
pages = ["I'm a customized navigator!", embed, "I'm the last page!"]
# Define our custom buttons for this navigator, keep in mind the order
# All navigator items MUST subclass nav.NavItem
items: list[nav.NavItem] = [
nav.PrevButton(),
nav.StopButton(),
nav.NextButton(),
MyNavButton()
]
# Pass our list of NavButton to the navigator
navigator = nav.NavigatorView(pages=pages, items=items)
# ... Send the navigator