imperazim / libform
Form library for PocketMine plugins
Requires
- php: ^8.2
Requires (Dev)
- phpstan/phpstan: ^1.10
- pocketmine/pocketmine-mp: ^5.0
This package is auto-updated.
Last update: 2026-07-24 05:00:48 UTC
README
LibForm
Description
A comprehensive form library for PocketMine-MP that simplifies the creation and management of Minecraft Bedrock Edition forms, supporting class-based definitions, fluent dynamic builders, pagination, form chaining, conditional elements, async data loading, timeouts, and ready-made presets.
Features
- Three form types: Long forms (button lists), modal dialogs (yes/no), and custom forms (inputs, toggles, sliders, dropdowns).
- Class-based and dynamic approaches: Extend abstract classes for reusable form definitions, or use fluent method chaining for quick one-off forms.
- FormBuilder shorthand: Ultra-concise form creation through
FormBuilder::long(),FormBuilder::modal(), andFormBuilder::custom(). - Pagination: Automatically paginate large button lists with
PaginatedLongForm. - Dynamic buttons: Generate buttons at runtime from data sources with
DynamicButtonForm. - Form chaining: Build multi-step wizards with
FormChain, supporting conditional step skipping. - Conditional elements: Show or hide form elements based on trigger values with
ConditionalForm. - Async data loading: Load form content asynchronously with
AsyncFormData, displaying a loading screen while data is fetched. - Form history: Stack-based back-button navigation with
FormHistory. - Form timeouts: Automatically close forms after a set duration with
FormTimeout. - Presets: Common form patterns (confirm dialog, player selector, color picker, number input, text input) via
FormPresets. - Server-side validation: Validate text inputs with regex, length constraints, or custom closures using
ValidatedInput. - Searchable dropdowns: Filter dropdown options at runtime with
SearchableDropdown. - State management: Share data between forms using the array-accessible
FormDatacontainer. - Flow control: Return
FormResult::CLOSEorFormResult::KEEPto control whether a form closes or re-opens after interaction.
How to Use
Add LibForm to your project with Composer:
composer require imperazim/libform
Then import classes under the imperazim\form namespace. All form types require PHP 8.2+ and PocketMine-MP API 5.0.0.
Components
imperazim\form
Highlights
Form-- abstract base class implementingpocketmine\form\Form. ProvidessendTo(),sendWithHistory(), and JSON serialization.FormResult-- enum withCLOSEandKEEPcases to control post-interaction behavior.FormData-- array-accessible data container (ArrayAccess,IteratorAggregate,Countable) for sharing state between forms.LibForm-- plugin entry point for standalone usage.
Usage
use imperazim\form\FormData; use imperazim\form\FormResult; // Create a shared data container $formData = new FormData([ 'playerName' => $player->getName(), 'score' => 1000, ]); // Access values $name = $formData->get('playerName'); $score = $formData['score']; // Check existence $formData->has('playerName'); // true // Flow control in form callbacks return FormResult::CLOSE; // close the form return FormResult::KEEP; // re-send the form
imperazim\form\base\elements
Highlights
TextElement-- abstract base for text-based elements, implementsJsonSerializable.Title-- represents a form title. ExtendsTextElement.Content-- represents form body text. ExtendsTextElement.
Usage
use imperazim\form\base\elements\Title; use imperazim\form\base\elements\Content; $title = new Title('My Form'); $content = new Content('Select an option below:'); $title->getText(); // "My Form" $content->getText(); // "Select an option below:"
imperazim\form\long
Highlights
LongForm-- abstract class for scrollable button-list forms. Extend and overridetitle(),content(), andbuttons(). Passtrueas the third constructor argument to auto-send.DynamicLongForm-- fluent builder for long forms. Create withDynamicLongForm::create()orDynamicLongForm::build(), chain methods, then callsendTo().DynamicButtonForm-- long form whose buttons are generated from a factory closure at send time. Supports optional caching and cache invalidation.PaginatedLongForm-- automatically splits a largeButtonCollectioninto pages with "Previous" / "Next" navigation buttons.
Usage
Class-based LongForm:
use pocketmine\player\Player; use imperazim\form\FormData; use imperazim\form\FormResult; use imperazim\form\long\LongForm; use imperazim\form\base\elements\Title; use imperazim\form\base\elements\Content; use imperazim\form\long\elements\Button; use imperazim\form\long\elements\ButtonTexture; use imperazim\form\long\elements\ButtonCollection; use imperazim\form\long\response\ButtonResponse; class MyListForm extends LongForm { protected function title(Player $player, FormData $data): Title { return new Title('Main Menu'); } protected function content(Player $player, FormData $data): Content { return new Content('Select an option:'); } protected function buttons(Player $player, FormData $data): ButtonCollection { return ButtonCollection::fromArray([ new Button( 'Play', new ButtonTexture('textures/ui/play', ButtonTexture::PATH), new ButtonResponse(function(Player $player): FormResult { $player->sendMessage("Let's go!"); return FormResult::CLOSE; }) ), new Button( 'Settings', new ButtonTexture('', ButtonTexture::PATH), new ButtonResponse(fn(Player $p) => FormResult::CLOSE) ), ]); } } // Auto-send on construction: new MyListForm($player, new FormData(), true);
DynamicLongForm (fluent):
use imperazim\form\FormResult; use imperazim\form\long\DynamicLongForm; DynamicLongForm::create("Quick Menu") ->setContent("What do you want to do?") ->addButton("Status", 'textures/blocks/diamond_block', function(Player $p): FormResult { $p->sendMessage("Status chosen!"); return FormResult::CLOSE; }) ->addButton("Settings", null, fn(Player $p) => FormResult::CLOSE) ->setOnClose(fn(Player $p) => FormResult::CLOSE) ->sendTo($player);
DynamicButtonForm (runtime-generated buttons):
use pocketmine\Server; use imperazim\form\FormResult; use imperazim\form\long\DynamicButtonForm; use imperazim\form\long\elements\Button; use imperazim\form\long\elements\ButtonTexture; use imperazim\form\long\elements\ButtonCollection; use imperazim\form\long\response\ButtonResponse; DynamicButtonForm::send( $player, "Online Players", "Select a player:", function(): ButtonCollection { $buttons = new ButtonCollection(); foreach (Server::getInstance()->getOnlinePlayers() as $p) { $buttons->add(new Button( $p->getName(), new ButtonTexture('', ButtonTexture::PATH), new ButtonResponse(fn(Player $pl) => FormResult::CLOSE) )); } return $buttons; }, fn(Player $p, Button $btn, int $idx) => FormResult::CLOSE );
PaginatedLongForm:
use imperazim\form\FormResult; use imperazim\form\long\PaginatedLongForm; use imperazim\form\long\elements\Button; use imperazim\form\long\elements\ButtonCollection; $allButtons = new ButtonCollection(); for ($i = 1; $i <= 50; $i++) { $allButtons->add(new Button( "Item #$i", new ButtonTexture('', ButtonTexture::PATH), new ButtonResponse(fn(Player $p) => FormResult::CLOSE) )); } $form = new PaginatedLongForm( player: $player, title: "Shop Items", content: "Select an item to buy:", buttons: $allButtons, onSelect: fn(Player $p, Button $btn, int $globalIndex) => FormResult::CLOSE, perPage: 8 ); $form->sendTo($player);
imperazim\form\long\elements
Highlights
Button-- represents a form button with text, aButtonTexture, and aButtonResponsecallback. ImplementsJsonSerializable.ButtonTexture-- defines a button icon source. UseButtonTexture::PATHfor resource pack paths orButtonTexture::URLfor remote URLs.ButtonCollection-- immutable, countable, iterable collection ofButtonobjects. SupportsArrayAccess,fromArray(), andgetByIndex().
Usage
use imperazim\form\long\elements\Button; use imperazim\form\long\elements\ButtonTexture; use imperazim\form\long\elements\ButtonCollection; use imperazim\form\long\response\ButtonResponse; use imperazim\form\FormResult; // Create a button with a path-based texture $button = new Button( 'Diamond Sword', new ButtonTexture('textures/items/diamond_sword', ButtonTexture::PATH), new ButtonResponse(fn(Player $p) => FormResult::CLOSE) ); $button->getText(); // "Diamond Sword" $button->getTexture(); // ButtonTexture instance $button->getResponse(); // ButtonResponse instance // Create a button with a URL-based texture $urlButton = new Button( 'Website', new ButtonTexture('https://example.com/icon.png', ButtonTexture::URL), new ButtonResponse(fn(Player $p) => FormResult::CLOSE) ); // Build a collection $collection = ButtonCollection::fromArray([$button, $urlButton]); $collection->count(); // 2 $collection->getByIndex(0); // first Button
imperazim\form\long\response
Highlights
ButtonResponse-- wraps aClosurethat handles button clicks. The closure receives aPlayerand must return aFormResult.
Usage
use pocketmine\player\Player; use imperazim\form\FormResult; use imperazim\form\long\response\ButtonResponse; $response = new ButtonResponse(function(Player $player): FormResult { $player->sendMessage("Button clicked!"); return FormResult::CLOSE; }); $result = $response->handle($player); // FormResult::CLOSE
imperazim\form\modal
Highlights
ModalForm-- abstract class for two-button confirmation dialogs. Extend and overridetitle(),content(),button1(),button2(),onConfirm(), andonCancel().DynamicModalForm-- fluent builder for modal forms. SupportssetContent(),setButton1(),setButton2(),setOnClose(), and the staticbuild()configurator pattern.
Usage
Class-based ModalForm:
use pocketmine\player\Player; use imperazim\form\FormData; use imperazim\form\FormResult; use imperazim\form\modal\ModalForm; use imperazim\form\modal\elements\ModalButton; use imperazim\form\base\elements\Title; use imperazim\form\base\elements\Content; class DeleteConfirmForm extends ModalForm { protected function title(Player $player, FormData $data): Title { return new Title('Delete Item'); } protected function content(Player $player, FormData $data): Content { return new Content('Are you sure you want to delete this item?'); } protected function button1(Player $player, FormData $data): ModalButton { return ModalButton::confirm('Yes, delete'); } protected function button2(Player $player, FormData $data): ModalButton { return ModalButton::cancel('Cancel'); } protected function onConfirm(Player $player, FormData $data): FormResult { $player->sendMessage('Item deleted!'); return FormResult::CLOSE; } protected function onCancel(Player $player, FormData $data): FormResult { return FormResult::CLOSE; } } new DeleteConfirmForm($player, new FormData(), true);
DynamicModalForm (fluent):
use pocketmine\player\Player; use imperazim\form\FormResult; use imperazim\form\modal\DynamicModalForm; use imperazim\form\modal\response\ModalResponse; DynamicModalForm::create("Save Changes") ->setContent("Do you want to save your changes?") ->setButton1("Save", function(Player $p, ModalResponse $r): FormResult { $p->sendMessage('Changes saved!'); return FormResult::CLOSE; }) ->setButton2("Discard", function(Player $p, ModalResponse $r): FormResult { $p->sendMessage('Changes discarded.'); return FormResult::CLOSE; }) ->sendTo($player);
imperazim\form\modal\elements
Highlights
ModalButton-- represents a modal dialog button. Created via named constructorsModalButton::confirm($label)andModalButton::cancel($label). Associates with aModalResulttype.
Usage
use imperazim\form\modal\elements\ModalButton; $yes = ModalButton::confirm('Yes'); $no = ModalButton::cancel('No'); $yes->getText(); // "Yes" $yes->getType(); // ModalResult::CONFIRM
imperazim\form\modal\response
Highlights
ModalResponse-- value object wrapping aModalResult. ProvidesisConfirmed(),isCanceled(), andgetResult().ModalResult-- enum withCONFIRMandCANCELcases.
Usage
use imperazim\form\modal\response\ModalResponse; use imperazim\form\modal\result\ModalResult; $response = ModalResponse::from(true); $response->isConfirmed(); // true $response->isCanceled(); // false $response->getResult(); // ModalResult::CONFIRM
imperazim\form\custom
Highlights
CustomForm-- abstract class for forms with multiple input elements. Extend and overridetitle(),elements(),onSubmit(), andonClose(). SupportsValidatedInputserver-side validation.DynamicCustomForm-- fluent builder for custom forms. UseaddElement(),setOnSubmit(),setOnClose(), and the staticbuild()configurator pattern.
Usage
Class-based CustomForm:
use pocketmine\player\Player; use imperazim\form\FormData; use imperazim\form\FormResult; use imperazim\form\custom\CustomForm; use imperazim\form\custom\elements\ElementCollection; use imperazim\form\custom\elements\Input; use imperazim\form\custom\elements\Toggle; use imperazim\form\custom\elements\Slider; use imperazim\form\custom\elements\Dropdown; use imperazim\form\custom\elements\Option; use imperazim\form\custom\response\CustomResponse; use imperazim\form\base\elements\Title; class SettingsForm extends CustomForm { protected function title(Player $player, FormData $data): Title { return new Title('Settings'); } protected function elements(Player $player, FormData $data): ElementCollection { return ElementCollection::fromArray([ new Input('username', 'Username:', 'Type your name', $player->getName()), new Toggle('notifications', 'Enable notifications?', true), new Slider('volume', 'Volume', 0, 100, 1, 50), new Dropdown('language', 'Language', [ new Option('en', 'English'), new Option('es', 'Spanish'), ], 'en'), ]); } protected function onSubmit(Player $player, CustomResponse $response): FormResult { $name = $response->getInput('username'); $volume = $response->getSlider('volume'); $lang = $response->getDropdown('language'); $player->sendMessage("Saved: $name, vol=$volume, lang={$lang->getId()}"); return FormResult::CLOSE; } protected function onClose(Player $player, FormData $data): FormResult { return FormResult::CLOSE; } } new SettingsForm($player, new FormData(), true);
DynamicCustomForm (fluent):
use pocketmine\player\Player; use imperazim\form\FormResult; use imperazim\form\custom\DynamicCustomForm; use imperazim\form\custom\elements\Input; use imperazim\form\custom\elements\Toggle; use imperazim\form\custom\response\CustomResponse; DynamicCustomForm::create("Player Profile") ->addElement(new Input('nickname', 'Nickname:', 'Enter nickname...', $player->getName())) ->addElement(new Toggle('pvp', 'Enable PvP?', false)) ->setOnSubmit(function(Player $p, CustomResponse $response): FormResult { $nick = $response->getInput('nickname'); $pvp = $response->getToggle('pvp') ? 'enabled' : 'disabled'; $p->sendMessage("Nickname: $nick | PvP: $pvp"); return FormResult::CLOSE; }) ->sendTo($player);
imperazim\form\custom\elements
Highlights
Element-- abstract base class for all custom form elements. ProvidesgetId(),hasId(), andhasValue().ElementCollection-- immutable, countable, iterable collection ofElementobjects. SupportsArrayAccess,fromArray(), andgetByIndex().Input-- text input field with ID, label, placeholder, and default value.ValidatedInput-- extendsElementwith server-side validation: regex pattern, min/max length, custom validator closure, and configurable error message.Toggle-- on/off boolean switch.Slider-- numeric range selector with min, max, step, and default. Validates that min < max and step > 0.Dropdown-- single-select option list. UsesOptionNormalizerTraitfor flexible option input formats.StepSlider-- visual step selector, similar toDropdown. ProvidesgetStepByIndex()andgetSelectedStep()aliases.SearchableDropdown-- dropdown with runtime filtering viasearch()andsetOptions(). Supports a placeholder text.Label-- non-interactive text element. ReturnsfalsefromhasValue().Option-- value object representing a selectable option with anidand displaytext.OptionNormalizerTrait-- shared trait used byDropdown,StepSlider, andSearchableDropdown. Normalizes raw arrays intoOption[]and resolves default indices.
Usage
use imperazim\form\custom\elements\Input; use imperazim\form\custom\elements\ValidatedInput; use imperazim\form\custom\elements\Toggle; use imperazim\form\custom\elements\Slider; use imperazim\form\custom\elements\Dropdown; use imperazim\form\custom\elements\StepSlider; use imperazim\form\custom\elements\SearchableDropdown; use imperazim\form\custom\elements\Label; use imperazim\form\custom\elements\Option; use imperazim\form\custom\elements\ElementCollection; // Input $input = new Input('name', 'Your Name:', 'Enter name...', 'Steve'); // ValidatedInput with regex and length constraints $email = new ValidatedInput( 'email', 'Email:', 'user@example.com', '', pattern: '/^[^@]+@[^@]+\.[a-z]+$/i', minLength: 5, maxLength: 64, errorMessage: 'Invalid email format' ); // ValidatedInput with custom closure $age = new ValidatedInput( 'age', 'Age:', '', '', validator: fn(string $v) => is_numeric($v) && (int)$v >= 13, errorMessage: 'You must be at least 13' ); // Toggle $toggle = new Toggle('pvp', 'Enable PvP?', false); // Slider $slider = new Slider('volume', 'Volume', 0, 100, 5, 50); // Dropdown with Option objects $dropdown = new Dropdown('color', 'Favorite Color', [ new Option('red', 'Red'), new Option('blue', 'Blue'), new Option('green', 'Green'), ], 'red'); // Dropdown with simple string array $dropdown2 = new Dropdown('mode', 'Game Mode', ['Survival', 'Creative', 'Adventure']); // StepSlider $stepper = new StepSlider('difficulty', 'Difficulty', [ new Option('easy', 'Easy'), new Option('normal', 'Normal'), new Option('hard', 'Hard'), ], 'normal'); // SearchableDropdown $searchable = new SearchableDropdown('kit', 'Select Kit:', [ new Option('warrior', 'Warrior'), new Option('archer', 'Archer'), new Option('mage', 'Mage'), ], placeholder: 'Type to search...'); $results = $searchable->search('war'); // filters matching options // Label (non-interactive) $label = new Label('Welcome to the settings menu!'); // Build a collection $collection = ElementCollection::fromArray([ $label, $input, $toggle, $slider, $dropdown, ]);
imperazim\form\custom\response
Highlights
CustomResponse-- encapsulates submitted form data. Provides typed getters:getInput(),getToggle(),getSlider(),getDropdown(),getStepSlider(), as well as genericgetString(),getInt(),getBool(),getFloat(),getArray(). Also exposesgetFormData(),getElement(),getElementsRaw(), andhas().SelectedOption-- value object returned by dropdown/step slider selections. ProvidesgetIndex(),getId(), andgetText().
Usage
use imperazim\form\custom\response\CustomResponse; use imperazim\form\custom\response\SelectedOption; // Inside an onSubmit callback: $name = $response->getInput('username'); // string $enabled = $response->getToggle('notifications'); // bool $volume = $response->getSlider('volume'); // float $language = $response->getDropdown('language'); // SelectedOption $language->getId(); // "en" $language->getText(); // "English" $language->getIndex(); // 0 // Generic access $response->getString('username'); $response->getInt('score', 0); $response->getBool('pvp', false); $response->has('username'); // true
imperazim\form\confirm
Highlights
ConfirmForm-- a ready-madeModalFormsubclass for quick yes/no confirmation dialogs. Accepts title, content, confirm/cancel callbacks, and custom button labels. UseConfirmForm::send()for a one-liner.
Usage
use pocketmine\player\Player; use imperazim\form\FormResult; use imperazim\form\confirm\ConfirmForm; // One-liner static send ConfirmForm::send( $player, "Delete Warp", "Are you sure you want to delete this warp?", function(Player $p): FormResult { $p->sendMessage("Warp deleted!"); return FormResult::CLOSE; }, function(Player $p): FormResult { $p->sendMessage("Cancelled."); return FormResult::CLOSE; }, confirmLabel: 'Yes, delete', cancelLabel: 'Keep it' );
imperazim\form\history
Highlights
FormHistory-- static stack-based form history for back-button navigation. Stores forms per player usingSplStack. Providespush(),back(),hasHistory(),clear(), andcleanup().
Usage
use imperazim\form\history\FormHistory; // Push current form before navigating to a new one FormHistory::push($player, $currentForm); $nextForm->sendTo($player); // Go back to the previous form $previousForm = FormHistory::back($player); // re-sends automatically // Check if back navigation is available if (FormHistory::hasHistory($player)) { // Show a "Back" button } // Clean up on player quit FormHistory::cleanup($player);
imperazim\form\builder
Highlights
FormBuilder-- static entry point withcustom(),long(), andmodal()methods returning specialized builders.LongFormBuilder-- fluent builder wrappingDynamicLongForm. Methods:content(),button(),onClose(),build(),send().ModalFormBuilder-- fluent builder wrappingDynamicModalForm. Methods:content(),accept(),deny(),onClose(),build(),send().CustomFormBuilder-- fluent builder wrappingDynamicCustomForm. Methods:input(),toggle(),slider(),dropdown(),stepSlider(),label(),onSubmit(),onClose(),build(),send().
Usage
use pocketmine\player\Player; use imperazim\form\FormResult; use imperazim\form\builder\FormBuilder; // Long form FormBuilder::long("Menu") ->content("Choose an option:") ->button("Play", fn(Player $p) => FormResult::CLOSE) ->button("Shop", fn(Player $p) => FormResult::CLOSE, "textures/items/diamond") ->send($player); // Modal form FormBuilder::modal("Confirm") ->content("Are you sure?") ->accept("Yes", fn(Player $p, $r) => FormResult::CLOSE) ->deny("No", fn(Player $p, $r) => FormResult::CLOSE) ->send($player); // Custom form FormBuilder::custom("Settings") ->label("Configure your preferences:") ->input("name", "Player Name", placeholder: "Enter name") ->toggle("pvp", "Enable PvP", default: true) ->slider("volume", "Volume", 0, 100, 1, 50) ->dropdown("mode", "Game Mode", ["Survival", "Creative"]) ->stepSlider("difficulty", "Difficulty", ["Easy", "Normal", "Hard"]) ->onSubmit(fn(Player $p, $r) => FormResult::CLOSE) ->send($player);
imperazim\form\preset
Highlights
FormPresets-- static utility class providing ready-made form templates:confirm()-- yes/no confirmation dialog.numberInput()-- slider-based numeric input with validation.playerSelector()-- button list of all online players (optionally excluding the sender).colorPicker()-- Minecraft color code selector.textInput()-- single text input form.
Usage
use pocketmine\player\Player; use imperazim\form\preset\FormPresets; // Confirm dialog FormPresets::confirm($player, "Delete", "Are you sure?", function(Player $p) { $p->sendMessage("Deleted!"); }); // Number input FormPresets::numberInput($player, "Set Level", "Choose level:", function(Player $p, $value) { $p->sendMessage("Level set to $value"); }, min: 1, max: 50, step: 1, default: 10); // Player selector FormPresets::playerSelector($player, "Choose Player", function(Player $sender, Player $target) { $sender->sendMessage("Selected: " . $target->getName()); }); // Color picker FormPresets::colorPicker($player, function(Player $p, string $colorCode) { $p->sendMessage($colorCode . "You picked this color!"); }); // Text input FormPresets::textInput($player, "Rename", "New name:", function(Player $p, string $text) { $p->sendMessage("Renamed to: $text"); }, placeholder: "Enter new name...");
imperazim\form\async
Highlights
AsyncFormData-- populates form elements via async callbacks. Shows a "Loading..." form while data is being fetched, then re-sends with the loaded content on the next tick. Provides:customForm()-- async custom form with dynamically loaded elements.longForm()-- async long form with dynamically loaded buttons.
Usage
use Closure; use pocketmine\player\Player; use imperazim\form\FormResult; use imperazim\form\async\AsyncFormData; use imperazim\form\custom\elements\Dropdown; use imperazim\form\custom\elements\Option; // Async custom form AsyncFormData::customForm( $plugin, $player, "Shop", function(Closure $resolve) { // Simulate async operation (DB query, HTTP request, etc.) $resolve([ new Dropdown("item", "Choose item", [ new Option("sword", "Sword"), new Option("shield", "Shield"), ]), ]); }, function(Player $p, $response): FormResult { $item = $response->getDropdown('item'); $p->sendMessage("You chose: " . $item->getText()); return FormResult::CLOSE; } ); // Async long form AsyncFormData::longForm( $plugin, $player, "Warps", "Select a warp:", function(Closure $resolve) { $resolve(["Spawn" => null, "PvP" => null, "Shop" => null]); }, function(Player $p, string $buttonText): FormResult { $p->sendMessage("Teleporting to $buttonText..."); return FormResult::CLOSE; } );
imperazim\form\conditional
Highlights
ConditionalForm-- form with elements that appear or disappear based on trigger element values. When a trigger changes, the form is automatically rebuilt and re-sent with the updated element set.
Usage
use pocketmine\player\Player; use imperazim\form\FormResult; use imperazim\form\conditional\ConditionalForm; use imperazim\form\custom\elements\Toggle; use imperazim\form\custom\elements\Input; use imperazim\form\custom\elements\Slider; $form = new ConditionalForm("Settings"); // Base elements (always shown) $form->addElement(new Toggle("advanced", "Advanced Mode")); $form->addElement(new Input("name", "Display Name:", "Enter name...")); // Conditional elements (shown only when "advanced" is true) $form->when("advanced", true, function() { return [ new Input("customPrefix", "Custom Prefix:", "[Prefix]"), new Slider("particleCount", "Particle Count", 0, 100, 1, 10), ]; }); $form->onSubmit(function(Player $p, $response): FormResult { $p->sendMessage("Settings saved!"); return FormResult::CLOSE; }); $form->send($player);
imperazim\form\chain
Highlights
FormChain-- orchestrates a sequence of forms shown one after another (wizard/stepper pattern). Each step receives accumulated data from previous steps. Supports conditional step skipping, completion callbacks, and cancellation handling.
Usage
use pocketmine\player\Player; use imperazim\form\FormData; use imperazim\form\chain\FormChain; FormChain::create($player) ->step(fn(Player $p, FormData $data) => new NameForm($p, $data)) ->step(fn(Player $p, FormData $data) => new AgeForm($p, $data)) ->step( fn(Player $p, FormData $data) => new ConfirmForm($p, $data), skip: fn(FormData $d) => $d['skipConfirm'] ?? false ) ->onComplete(function(Player $p, FormData $data) { $p->sendMessage("Registration complete! Name: " . $data['name']); }) ->onCancel(function(Player $p, FormData $data, int $step) { $p->sendMessage("Cancelled at step $step."); }) ->start(); // Inside each step form, call $chain->advance(['key' => 'value']) to proceed // or $chain->cancel() to abort the chain.
imperazim\form\timeout
Highlights
FormTimeout-- wraps any form with an automatic timeout that closes it after a specified number of seconds. Manages active timeout tasks per player, automatically cancelling previous timeouts. Providessend(),cancel(), andcancelAll().
Usage
use pocketmine\player\Player; use imperazim\form\timeout\FormTimeout; // Send a form that auto-closes after 30 seconds $form = new MyLongForm($player, $data); FormTimeout::send($plugin, $player, $form, seconds: 30, onTimeout: function(Player $p) { $p->sendMessage("Form timed out! Please try again."); }); // Manually cancel a timeout FormTimeout::cancel($player->getId()); // Cancel all active timeouts (e.g. on plugin disable) FormTimeout::cancelAll();
Licensing information
This project is licensed under MIT. Please see the LICENSE file for details.