Skip to main content

A library provides interactive ui for discord.py

Project description

ductile-ui

PyPI - Version PyPI - Python Version

A library provides declarative UI for discord.py.

Features

  • Declarative UI, inspired by React.
  • Component-oriented with State
  • Fully typed

Installation

Python3.10 or higher is required

discord.py^2.2.0 is required; any compatibility under 2.1.x or 1.x is not guaranteed

Using the latest stable release of discord.py is recommended

  pip install ductile-ui

Usage/Examples

You can define component as return value of View.render(). To store state, use State.

# This example requires the 'message_content' privileged intent to function.


import random

import discord
from discord.ext import commands
from ductile import State, View, ViewObject
from ductile.controller import MessageableController
from ductile.ui import Button


class Bot(commands.Bot):
    def __init__(self) -> None:
        super().__init__(command_prefix="!", intents=discord.Intents.all())

    async def on_ready(self) -> None:
        print(f"Logged in as {self.user}")
        print("Ready!")


class CounterView(View):
    def __init__(self) -> None:
        super().__init__()
        self.count = State(0, self)

    def render(self) -> ViewObject:
        e = discord.Embed(title="Counter", description=f"Count: {self.count.get_state()}")

        async def handle_increment(interaction: discord.Interaction) -> None:
            await interaction.response.defer()
            self.count.set_state(lambda x: x + 1)

        async def handle_decrement(interaction: discord.Interaction) -> None:
            await interaction.response.defer()
            self.count.set_state(lambda x: x - 1)

        async def stop(interaction: discord.Interaction) -> None:
            await interaction.response.defer()
            self.stop()

        # Define UI using ViewObject
        return ViewObject(
            embeds=[e],
            components=[
                Button("+1", style={"color": "blurple", "row": 0}, on_click=handle_increment),
                Button("-1", style={"color": "blurple", "row": 0}, on_click=handle_decrement),
                Button(
                    "random",
                    style={"color": "green", "row": 1},
                    # if you passed synchronous function to Button.on_click,
                    # library automatically calls `await interaction.response.defer()`.
                    on_click=lambda _: self.count.set_state(random.randint(0, 100)),
                ),
                Button("stop", style={"color": "red", "row": 1}, on_click=stop),
            ],
        )


bot = Bot()


@bot.command(name="counter")
async def send_counter(ctx: commands.Context) -> None:
    controller = MessageableController(CounterView(), messageable=ctx.channel)
    await controller.send()
    timed_out, states = await controller.wait()
    await ctx.send(f"Timed out: {timed_out}\nCount: {states['count']}")


bot.run("MY_COOL_BOT_TOKEN")

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

ductile_ui-0.2.6.tar.gz (14.8 kB view hashes)

Uploaded Source

Built Distribution

ductile_ui-0.2.6-py3-none-any.whl (20.4 kB view hashes)

Uploaded Python 3

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page