Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨ Add native interaction modal support #88

Merged
merged 1 commit into from
Jun 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/Commands/AbstractCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,13 @@
use Discord\Parts\Guild\Guild;
use Discord\Parts\User\User;
use Illuminate\Support\Str;
use Laracord\Discord\Concerns\HasModal;
use Laracord\Laracord;

abstract class AbstractCommand
{
use HasModal;

/**
* The bot instance.
*
Expand Down
17 changes: 17 additions & 0 deletions src/Discord/Concerns/HasModal.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

namespace Laracord\Discord\Concerns;

use Discord\Parts\Interactions\Interaction;
use Laracord\Discord\Modal;

trait HasModal
{
/**
* Retrieve a modal instance.
*/
public function modal(?string $title = null, ?Interaction $interaction = null): Modal
{
return Modal::make($title, $interaction);
}
}
197 changes: 197 additions & 0 deletions src/Discord/Modal.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
<?php

namespace Laracord\Discord;

use Discord\Builders\Components\ActionRow;
use Discord\Builders\Components\TextInput;
use Discord\Parts\Interactions\Interaction;
use Exception;
use Illuminate\Support\Str;
use React\Promise\ExtendedPromiseInterface;

class Modal
{
/**
* The interaction instance.
*/
protected ?Interaction $interaction = null;

/**
* The modal title.
*/
protected string $title = '';

/**
* The modal ID.
*/
protected ?string $id = null;

/**
* The modal components.
*/
protected array $components = [];

/**
* The modal submit callback.
*
* @var callable|null
*/
protected $submit = null;

/**
* Create a new Discord modal instance
*/
public function __construct(?string $title = null, ?Interaction $interaction = null)
{
$this->title = $title;
$this->interaction = $interaction;
}

/**
* Make a new Discord modal instance
*/
public static function make(?string $title = null, ?Interaction $interaction = null): self
{
return new static($title, $interaction);
}

/**
* Set the modal title.
*/
public function title(string $title): self
{
$this->title = $title;

return $this;
}

/**
* Set the modal ID.
*/
public function id(string $id): self
{
$this->id = $id;

return $this;
}

/**
* Set the modal components.
*/
public function components(array $components): self
{
$this->components = [...$this->components, ...$components];

return $this;
}

/**
* Set the modal submit callback.
*/
public function submit(callable $submit): self
{
$this->submit = $submit;

return $this;
}

/**
* Add a text input component to the modal.
*/
public function text(
string $label,
?string $key = null,
?int $minLength = null,
?int $maxLength = null,
?string $placeholder = null,
?string $value = null,
bool $required = false
): self {
$this->components[] = TextInput::new($label, TextInput::STYLE_SHORT)
->setCustomId($key ?? Str::camel($label))
->setMinLength($minLength)
->setMaxLength($maxLength)
->setPlaceholder($placeholder)
->setValue($value)
->setRequired($required);

return $this;
}

/**
* Add a paragraph input component to the modal.
*/
public function paragraph(
string $label,
?string $key = null,
?int $minLength = null,
?int $maxLength = null,
?string $placeholder = null,
?string $value = null,
bool $required = false
): self {
$this->components[] = TextInput::new($label, TextInput::STYLE_PARAGRAPH)
->setCustomId($key ?? Str::camel($label))
->setMinLength($minLength)
->setMaxLength($maxLength)
->setPlaceholder($placeholder)
->setValue($value)
->setRequired($required);

return $this;
}

/**
* Show the modal.
*/
public function show(?Interaction $interaction = null): ExtendedPromiseInterface
{
$interaction = $interaction ?? $this->interaction;

return $interaction->showModal(
$this->getTitle(),
$this->getId() ?? Str::camel($this->getTitle()),
$this->getComponents(),
$this->getSubmit()
);
}

/**
* Retrieve the modal components.
*/
public function getComponents(): array
{
$components = collect($this->components)
->map(fn ($component) => ActionRow::new()->addComponent($component));

if ($components->isEmpty()) {
throw new Exception('The modal must have at least one component.');
}

return $components->all();
}

/**
* Retrieve the modal title.
*/
public function getTitle(): string
{
return $this->title;
}

/**
* Retrieve the modal ID.
*/
public function getId(): ?string
{
return $this->id;
}

/**
* Retrieve the modal submit callback.
*/
public function getSubmit(): ?callable
{
return $this->submit;
}
}
Loading