Skip to content

ImperaZim/LibForm

Repository files navigation

LibForm

Version 2.0.0 PocketMine-MP 5.0.0+ PHP 8.2+ License

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(), and FormBuilder::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 FormData container.
  • Flow control: Return FormResult::CLOSE or FormResult::KEEP to 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 implementing pocketmine\form\Form. Provides sendTo(), sendWithHistory(), and JSON serialization.
  • FormResult -- enum with CLOSE and KEEP cases 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, implements JsonSerializable.
  • Title -- represents a form title. Extends TextElement.
  • Content -- represents form body text. Extends TextElement.

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 override title(), content(), and buttons(). Pass true as the third constructor argument to auto-send.
  • DynamicLongForm -- fluent builder for long forms. Create with DynamicLongForm::create() or DynamicLongForm::build(), chain methods, then call sendTo().
  • DynamicButtonForm -- long form whose buttons are generated from a factory closure at send time. Supports optional caching and cache invalidation.
  • PaginatedLongForm -- automatically splits a large ButtonCollection into 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, a ButtonTexture, and a ButtonResponse callback. Implements JsonSerializable.
  • ButtonTexture -- defines a button icon source. Use ButtonTexture::PATH for resource pack paths or ButtonTexture::URL for remote URLs.
  • ButtonCollection -- immutable, countable, iterable collection of Button objects. Supports ArrayAccess, fromArray(), and getByIndex().

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 a Closure that handles button clicks. The closure receives a Player and must return a FormResult.

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 override title(), content(), button1(), button2(), onConfirm(), and onCancel().
  • DynamicModalForm -- fluent builder for modal forms. Supports setContent(), setButton1(), setButton2(), setOnClose(), and the static build() 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 constructors ModalButton::confirm($label) and ModalButton::cancel($label). Associates with a ModalResult type.

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 a ModalResult. Provides isConfirmed(), isCanceled(), and getResult().
  • ModalResult -- enum with CONFIRM and CANCEL cases.

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 override title(), elements(), onSubmit(), and onClose(). Supports ValidatedInput server-side validation.
  • DynamicCustomForm -- fluent builder for custom forms. Use addElement(), setOnSubmit(), setOnClose(), and the static build() 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. Provides getId(), hasId(), and hasValue().
  • ElementCollection -- immutable, countable, iterable collection of Element objects. Supports ArrayAccess, fromArray(), and getByIndex().
  • Input -- text input field with ID, label, placeholder, and default value.
  • ValidatedInput -- extends Element with 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. Uses OptionNormalizerTrait for flexible option input formats.
  • StepSlider -- visual step selector, similar to Dropdown. Provides getStepByIndex() and getSelectedStep() aliases.
  • SearchableDropdown -- dropdown with runtime filtering via search() and setOptions(). Supports a placeholder text.
  • Label -- non-interactive text element. Returns false from hasValue().
  • Option -- value object representing a selectable option with an id and display text.
  • OptionNormalizerTrait -- shared trait used by Dropdown, StepSlider, and SearchableDropdown. Normalizes raw arrays into Option[] 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 generic getString(), getInt(), getBool(), getFloat(), getArray(). Also exposes getFormData(), getElement(), getElementsRaw(), and has().
  • SelectedOption -- value object returned by dropdown/step slider selections. Provides getIndex(), getId(), and getText().

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-made ModalForm subclass for quick yes/no confirmation dialogs. Accepts title, content, confirm/cancel callbacks, and custom button labels. Use ConfirmForm::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 using SplStack. Provides push(), back(), hasHistory(), clear(), and cleanup().

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 with custom(), long(), and modal() methods returning specialized builders.
  • LongFormBuilder -- fluent builder wrapping DynamicLongForm. Methods: content(), button(), onClose(), build(), send().
  • ModalFormBuilder -- fluent builder wrapping DynamicModalForm. Methods: content(), accept(), deny(), onClose(), build(), send().
  • CustomFormBuilder -- fluent builder wrapping DynamicCustomForm. 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. Provides send(), cancel(), and cancelAll().

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.

About

Form UI builder and response handling library for PocketMine-MP plugins.

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages