interactiveflow
v1.0.0
Published
Streamline your Discord UI with declarative Containers & Stateful Pagination.
Maintainers
Readme
✨ Features
- 🧱 Declarative Container Builder — Fluent, chainable API wrapping
ContainerBuilderfor clean, readable layouts. - 📄 Stateful Pagination Engine — Generic
FlowPaginator<T>that handles collectors, timeouts, and navigation automatically. - 🔒 Fully Type-Safe — Written in strict TypeScript with comprehensive JSDoc coverage on every public member.
- 📦 Dual Output — Ships ESM and CJS bundles via tsup with full declaration files.
- ⚡ Validation Built-In — Checks Discord's component limits at build time with descriptive
FlowErrormessages. - 🎯 Zero Config Pagination — Just provide your data, a render function, and call
send(). Everything else is handled.
📦 Installation
npm install interactiveflow# or with your preferred package manager
yarn add interactiveflow
pnpm add interactiveflowPeer Dependency: Requires
discord.jsv14 or higher.
🚀 Quick Start
Building a Static Container
Create a Components V2 container in just a few lines:
import { FlowContainer } from "interactiveflow";
import { ButtonBuilder, ButtonStyle, MessageFlags } from "discord.js";
const card = new FlowContainer({ accentColor: 0x5865f2 })
.addTitle("# 📋 Server Info")
.addSeparator()
.addDescription("Welcome to the server! Here's what we offer.")
.addSection({
content: "🔗 **Website**\nCheck out our homepage for updates.",
buttonAccessory: new ButtonBuilder()
.setLabel("Visit")
.setStyle(ButtonStyle.Link)
.setURL("https://example.com"),
});
await interaction.reply({
components: [card.toBuilder()],
flags: MessageFlags.IsComponentsV2,
});Paginated Lists
Turn any array into a navigable, paginated view with one class:
import { FlowContainer, FlowPaginator } from "interactiveflow";
const users = ["Alice", "Bob", "Charlie", "Dave", "Eve", "Frank", "Grace"];
const paginator = new FlowPaginator<string>({
data: users,
pageSize: 3,
idleTimeout: 30_000,
render: (items, pageIndex, totalPages) => {
const list = items
.map((name, i) => `**${pageIndex * 3 + i + 1}.** ${name}`)
.join("\n");
return new FlowContainer({ accentColor: 0x57f287 })
.addTitle("# 👥 User Directory")
.addSeparator()
.addDescription(list);
},
});
await paginator.send(interaction);The paginator automatically handles:
- ◀ Previous / Page X/Y / Next ▶ navigation buttons
- Filtering interactions to the original user
- Disabling buttons and cleaning up after the idle timeout
📖 API Reference
FlowContainer
A declarative wrapper around Discord.js ContainerBuilder.
Constructor
new FlowContainer(options?: FlowContainerOptions)| Option | Type | Description |
|---|---|---|
| accentColor | number | Accent color for the container sidebar. |
| spoiler | boolean | Whether to render as a spoiler. |
Methods
| Method | Returns | Description |
|---|---|---|
| .addTitle(text) | this | Add a title text display (supports markdown). |
| .addDescription(text) | this | Add a description text display. |
| .addSeparator(options?) | this | Add a separator. Options: { divider?: boolean, spacing?: "small" \| "large" } |
| .addSection(options) | this | Add a section with text + an optional buttonAccessory or thumbnailAccessory. |
| .addActionRow(...components) | this | Add an action row with interactive components. |
| .addComponent(component) | this | Escape hatch — add any raw discord.js container component. |
| .setAccentColor(color) | this | Set the container accent color. |
| .setSpoiler(spoiler) | this | Toggle the spoiler flag. |
| .getComponentCount() | number | Current number of top-level components. |
| .getRemainingCapacity() | number | Remaining slots before Discord's 10-component limit. |
| .toBuilder() | ContainerBuilder | Access the underlying discord.js builder. |
| .build() | APIContainerComponent | Serialize to API-ready JSON. |
All mutating methods return
thisfor chaining.
FlowPaginator<T>
A generic, stateful pagination engine.
Constructor
new FlowPaginator<T>(options: FlowPaginatorOptions<T>)| Option | Type | Default | Description |
|---|---|---|---|
| data | T[] | — | The full dataset to paginate. |
| pageSize | number | 5 | Items per page. |
| render | FlowPageRenderer<T> | — | Function receiving (items, pageIndex, totalPages) → FlowContainer. |
| idleTimeout | number | 60000 | Collector idle timeout in ms. |
Methods & Properties
| Member | Type | Description |
|---|---|---|
| .totalPages | number | Total number of pages (getter). |
| .getState() | PaginatorState | Snapshot: { currentPage, totalPages, active }. |
| .getPageData() | T[] | Data slice for the current page. |
| .renderPage(disabled?) | object | Render current page with nav buttons. |
| .send(target) | Promise<Message> | Send to a channel or reply to an interaction. Starts the collector. |
| .stop() | void | Manually stop the collector and disable buttons. |
FlowError
Custom error class with a code property for structured error handling.
try {
container.addTitle("...");
} catch (error) {
if (error instanceof FlowError && error.code === "COMPONENT_LIMIT") {
console.log("Too many components!");
}
}| Error Code | Source | Description |
|---|---|---|
| COMPONENT_LIMIT | FlowContainer | Container exceeds 10 components. |
| INVALID_SECTION | FlowContainer | Section has both button + thumbnail accessory. |
| EMPTY_DATA | FlowPaginator | Data array is empty. |
| INVALID_PAGE_SIZE | FlowPaginator | Page size is less than 1. |
| INVALID_TARGET | FlowPaginator | Unsupported send target. |
Constants
| Constant | Value | Description |
|---|---|---|
| MAX_CONTAINER_COMPONENTS | 10 | Max top-level components per container. |
| MAX_SECTION_TEXT_COMPONENTS | 3 | Max text items in a section. |
| MAX_ACTION_ROW_COMPONENTS | 5 | Max items in an action row. |
| DEFAULT_PAGE_SIZE | 5 | Default items per page. |
| DEFAULT_IDLE_TIMEOUT | 60000 | Default idle timeout (ms). |
📂 Examples
See the examples/ directory for complete, runnable demos:
basic-usage.ts— Static info card + paginated user directory.
🛠️ Development
# Install dependencies
npm install
# Build (ESM + CJS)
npm run build
# Watch mode
npm run dev
# Type-check
npm run lint🤝 Contributing
Contributions are welcome! Please read our Contributing Guide and Code of Conduct before getting started.
👤 Credits
Built and maintained by rly-dev.
📄 License
This project is licensed under the GNU General Public License v3.0.
