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