imperazim / libform
Form library for PocketMine plugins
Requires
- php: ^8.2
Requires (Dev)
- phpstan/phpstan: ^1.10
This package is auto-updated.
Last update: 2025-06-03 19:03:45 UTC
README
Form Library for PocketMine (Minecraft PE)
Overview
LibForm is a PHP library that simplifies the creation of Minecraft forms in PocketMine. It offers two approaches:
-
Class-based
Extend abstract classes to define form structure, elements, and behavior. Passingtrue
as the third constructor argument automatically sends the form to the player. -
Dynamic (Fluent Interface)
Build forms on-the-fly using method chaining. Ideal for quick, concise form creation without defining separate classes.
Supported form types:
- List Form (LongForm)
- Modal Form
- Custom Form
Installation
Add LibForm to your project with Composer:
composer require imperazim/libform
Then include classes under the imperazim\form
namespace.
Form Types
1. List Form (LongForm)
A scrollable list of buttons, optionally with custom textures or icons.
1.1. Class-based
-
Extend
LongForm
-
Override three methods:
title()
: returns aTitle
object.content()
: returns aContent
object.buttons()
: returns aButtonCollection
. EachButton
can have a texture and a callback viaButtonResponse
.
-
Instantiate with
true
to automatically send to the player.
use imperazim\form\long\LongForm; 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\base\Title; use imperazim\form\base\Content; class MyListForm extends LongForm { protected function title(Player $player, FormData $formData): Title { return new Title('Main Menu'); } protected function content(Player $player, FormData $formData): Content { return new Content('Select an option:'); } protected function buttons(Player $player, FormData $formData): ButtonCollection { return ButtonCollection::fromArray([ new Button( 'Option 1', new ButtonTexture('textures/ui/icon_recipe', ButtonTexture::PATH), new ButtonResponse(function(Player $player): FormResult { $player->sendMessage("You clicked Option 1!"); return FormResult::CLOSE; }) ), new Button( 'Option 2', null, new ButtonResponse(function(Player $player): FormResult { $player->sendMessage("Option 2 selected."); return FormResult::CLOSE; }) ), ]); } } // Instantiation sends the form immediately: new MyListForm($player, $formData, true);
1.2. Dynamic (Fluent Interface)
-
Call
DynamicLongForm::create($title)
. -
Chain methods:
setContent($text)
addButton($text, $texturePathOrNull, $callback)
sendTo($player)
use imperazim\form\long\DynamicLongForm; DynamicLongForm::create("Quick Menu") ->setContent("What do you want to do?") ->addButton( "Status", 'textures/blocks/diamond_block', function(Player $player): FormResult { $player->sendMessage("Status chosen!"); return FormResult::CLOSE; } ) ->addButton( "Settings", null, function(Player $player): FormResult { $player->sendMessage("Opening settings..."); return FormResult::CLOSE; } ) ->sendTo($player);
2. Modal Form
A two-button confirmation dialog (confirm/cancel).
2.1. Class-based
-
Extend
ModalForm
. -
Override four methods:
title()
: returns aTitle
.content()
: returns aContent
.button1()
: typicallyModalButton::confirm($text)
.button2()
: typicallyModalButton::cancel($text)
.
-
Implement
onConfirm()
to handle the “confirm” action. Optionally overrideonCancel()
for custom “cancel” behavior. -
Instantiate with
true
to send immediately.
use imperazim\form\modal\ModalForm; use imperazim\form\modal\elements\ModalButton; use imperazim\form\base\Title; use imperazim\form\base\Content; class ConfirmationForm extends ModalForm { protected function title(Player $player, FormData $formData): Title { return new Title('Confirmation'); } protected function content(Player $player, FormData $formData): Content { return new Content('Are you sure you want to delete this item?'); } protected function button1(Player $player, FormData $formData): ModalButton { return ModalButton::confirm('Yes'); } protected function button2(Player $player, FormData $formData): ModalButton { return ModalButton::cancel('No'); } protected function onConfirm(Player $player, FormData $formData): FormResult { $player->sendMessage('Item deleted!'); return FormResult::CLOSE; } // Optionally: // protected function onCancel(Player $player, FormData $formData): FormResult { ... } } // Sends the form automatically: new ConfirmationForm($player, $formData, true);
2.2. Dynamic (Fluent Interface)
-
Call
DynamicModalForm::create($title)
. -
Chain methods:
setContent($text)
setButton1($text, $callback)
setButton2($text, $callback)
sendTo($player)
use imperazim\form\modal\DynamicModalForm; DynamicModalForm::create("Save Changes") ->setContent("Do you want to save your changes?") ->setButton1("Save", function(Player $player, ModalResponse $response): FormResult { $player->sendMessage('Changes saved!'); return FormResult::CLOSE; }) ->setButton2("Cancel", function(Player $player, ModalResponse $response): FormResult { $player->sendMessage('Operation canceled.'); return FormResult::CLOSE; }) ->sendTo($player);
3. Custom Form
A flexible form with multiple input elements (text fields, toggles, sliders, dropdowns, etc.).
3.1. Class-based
-
Extend
CustomForm
. -
Override two methods:
title()
: returns aTitle
.elements()
: returns anElementCollection
built from individual element objects (Label
,Input
,Toggle
,Slider
,Dropdown
,StepSlider
).
-
Implement
onSubmit()
to process submitted values viaCustomResponse
. -
Instantiate with
true
to send immediately.
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\Title; class SettingsForm extends CustomForm { protected function title(Player $player, FormData $formData): Title { return new Title('General Settings'); } protected function elements(Player $player, FormData $formData): ElementCollection { return ElementCollection::fromArray([ new Input('username', 'Username:', 'Type your name', $player->getName()), new Toggle('notifications', 'Enable notifications?', true), new Slider('volume', 'Sound Volume', 0, 100, 1, 50), new Dropdown('language', 'Language', [ new Option('en', 'English'), new Option('es', 'Spanish'), new Option('pt', 'Portuguese') ], 'en') ]); } protected function onSubmit(Player $player, CustomResponse $response): FormResult { $username = $response->getInput('username'); $volume = $response->getSlider('volume'); $languageId = $response->getSelectedOption('language')->getId(); $player->sendMessage("Settings saved: $username, Volume $volume, Language $languageId"); return FormResult::CLOSE; } } // Sends the form automatically: new SettingsForm($player, $formData, true);
3.2. Dynamic (Fluent Interface)
-
Call
DynamicCustomForm::create($title)
. -
Chain methods:
addElement($elementObject)
for each element.setOnSubmit($callback)
to handle submission.sendTo($player)
to display.
use imperazim\form\custom\DynamicCustomForm; use imperazim\form\custom\elements\Input; use imperazim\form\custom\elements\Toggle; DynamicCustomForm::create("Player Profile") ->addElement(new Input('nickname', 'Nickname:', 'Enter your nickname...', $player->getName())) ->addElement(new Toggle('pvp', 'Enable PvP?', false)) ->setOnSubmit(function(Player $player, CustomResponse $response): FormResult { $nick = $response->getInput('nickname'); $pvpStatus = $response->getToggle('pvp') ? 'enabled' : 'disabled'; $player->sendMessage("Nickname: $nick | PvP: $pvpStatus"); return FormResult::CLOSE; }) ->sendTo($player);
CustomForm Elements
Element | Description | Example Creation |
---|---|---|
Label | Informational, non-interactive text | new Label('Welcome!') |
Input | Text input field | new Input('id', 'Label', 'Placeholder', 'Default value') |
Toggle | On/off switch | new Toggle('id', 'Enable feature?', true) |
Slider | Numeric range selector | new Slider('id', 'Volume', 0, 100, 5, 50) |
Dropdown | Single-select option list | new Dropdown('id', 'Choose a color', [new Option('r','Red')], 'r') |
StepSlider | Visual step selector | new StepSlider('id', 'Difficulty', [new Option('easy','Easy')], 'easy') |
State Management (FormData)
Use FormData
to share data between forms:
use imperazim\form\FormData; // Create FormData with initial values: $formData = new FormData([ 'playerName' => $player->getName(), 'score' => 1000, ]); // Instantiate FormData and optional, the parameter accepts arrays! // Retrieve values in any form: $playerName = $formData->get('playerName'); // string $score = $formData->get('score'); // int or $playerName = $formData['playerName']; // string $score = $formData['score']; // int
Flow Control (FormResult)
After a form interaction, return one of:
- FormResult::CLOSE — close the form for the player.
- FormResult::KEEP — keep the form open (e.g., for validation, re-prompt).
protected function onSubmit(Player $player, CustomResponse $response): FormResult { // If "name" is empty, show an error and keep the form open: if ($response->getInput('name') === '') { $player->sendMessage("The 'name' field cannot be empty!"); return FormResult::KEEP; } // Otherwise, close the form: return FormResult::CLOSE; }
Example: Test Command
This example registers a /testform
command to open different types of forms:
namespace your\plugin\namespace; use pocketmine\plugin\PluginBase; use pocketmine\command\Command; use pocketmine\command\CommandSender; use pocketmine\player\Player; use imperazim\form\FormData; use imperazim\form\long\DynamicLongForm; use imperazim\form\modal\DynamicModalForm; use imperazim\form\custom\DynamicCustomForm; class Main extends PluginBase { public function onEnable(): void { $this->getServer()->getCommandMap()->register('testform', new FormCommand()); } } class FormCommand extends Command { public function __construct() { parent::__construct("testform", "Test command for forms", "/testform <type>"); } public function execute(CommandSender $sender, string $label, array $args): void { if (!$sender instanceof Player) { $sender->sendMessage("This command can only be used by a player."); return; } $type = $args[0] ?? ''; switch (strtolower($type)) { case 'long': // Class-based ListForm (auto-sent) new MyListForm($sender, new FormData(), true); break; case 'long_dynamic': // Dynamic ListForm DynamicLongForm::create("Quick Menu") ->setContent("Choose:") ->addButton("Option A", null, fn(Player $p) => FormResult::CLOSE) ->sendTo($sender); break; case 'custom': // Class-based CustomForm (auto-sent) new SettingsForm($sender, new FormData(), true); break; case 'modal_dynamic': // Dynamic ModalForm DynamicModalForm::create("Confirmation") ->setContent("Do you wish to continue?") ->setButton1("Yes", fn(Player $p, $r) => FormResult::CLOSE) ->setButton2("No", fn(Player $p, $r) => FormResult::CLOSE) ->sendTo($sender); break; default: $sender->sendMessage("Usage: /testform <long|long_dynamic|custom|modal_dynamic>"); } } }