diff --git a/packages/actions/docs/04-modals.md b/packages/actions/docs/04-modals.md index 312bf08326..c8a1187381 100644 --- a/packages/actions/docs/04-modals.md +++ b/packages/actions/docs/04-modals.md @@ -506,6 +506,29 @@ use Filament\Support\View\Components\Modal; Modal::closedByClickingAway(false); ``` +## Closing the modal by hitting escape + +By default, when you hit escape on a modal, it will close itself. If you wish to disable this behavior for a specific action, you can use the `closedByHittingEscape(false)` method: + +```php +Action::make('updateAuthor') + ->form([ + // ... + ]) + ->action(function (array $data): void { + // ... + }) + ->closedByHittingEscape(false) +``` + +If you'd like to change the behaviour for all modals in the application, you can do so by calling `Modal::closedByHittingEscape()` inside a service provider or middleware: + +```php +use Filament\Support\View\Components\Modal; + +Modal::closedByHittingEscape(false); +``` + ## Hiding the modal close button By default, modals have a close button in the top right corner. If you wish to hide the close button, you can use the `modalCloseButton(false)` method: diff --git a/packages/actions/resources/views/components/modals.blade.php b/packages/actions/resources/views/components/modals.blade.php index d4e91b8217..eb38292739 100644 --- a/packages/actions/resources/views/components/modals.blade.php +++ b/packages/actions/resources/views/components/modals.blade.php @@ -8,6 +8,7 @@ :alignment="$action?->getModalAlignment()" :close-button="$action?->hasModalCloseButton()" :close-by-clicking-away="$action?->isModalClosedByClickingAway()" + :close-by-hitting-escape="$action?->isModalClosedByHittingEscape()" :description="$action?->getModalDescription()" display-classes="block" :extra-modal-window-attribute-bag="$action?->getExtraModalWindowAttributeBag()" @@ -68,6 +69,7 @@ :alignment="$action?->getModalAlignment()" :close-button="$action?->hasModalCloseButton()" :close-by-clicking-away="$action?->isModalClosedByClickingAway()" + :close-by-hitting-escape="$action?->isModalClosedByHittingEscape()" :description="$action?->getModalDescription()" display-classes="block" :extra-modal-window-attribute-bag="$action?->getExtraModalWindowAttributeBag()" @@ -122,6 +124,7 @@ :alignment="$action?->getModalAlignment()" :close-button="$action?->hasModalCloseButton()" :close-by-clicking-away="$action?->isModalClosedByClickingAway()" + :close-by-hitting-escape="$action?->isModalClosedByHittingEscape()" :description="$action?->getModalDescription()" display-classes="block" :extra-modal-window-attribute-bag="$action?->getExtraModalWindowAttributeBag()" @@ -182,6 +185,7 @@ :alignment="$action?->getModalAlignment()" :close-button="$action?->hasModalCloseButton()" :close-by-clicking-away="$action?->isModalClosedByClickingAway()" + :close-by-hitting-escape="$action?->isModalClosedByHittingEscape()" :description="$action?->getModalDescription()" display-classes="block" :extra-modal-window-attribute-bag="$action?->getExtraModalWindowAttributeBag()" @@ -242,6 +246,7 @@ :alignment="$action?->getModalAlignment()" :close-button="$action?->hasModalCloseButton()" :close-by-clicking-away="$action?->isModalClosedByClickingAway()" + :close-by-hitting-escape="$action?->isModalClosedByHittingEscape()" :description="$action?->getModalDescription()" display-classes="block" :extra-modal-window-attribute-bag="$action?->getExtraModalWindowAttributeBag()" diff --git a/packages/actions/src/Concerns/CanOpenModal.php b/packages/actions/src/Concerns/CanOpenModal.php index b36fa69916..264fbcb497 100644 --- a/packages/actions/src/Concerns/CanOpenModal.php +++ b/packages/actions/src/Concerns/CanOpenModal.php @@ -79,6 +79,7 @@ trait CanOpenModal protected bool | Closure | null $hasModalCloseButton = null; protected bool | Closure | null $isModalClosedByClickingAway = null; + protected bool | Closure | null $isModalClosedByHittingEscape = null; protected string | Closure | null $modalIcon = null; @@ -94,6 +95,13 @@ trait CanOpenModal return $this; } + public function closeModalByHittingEscape(bool | Closure | null $condition = true): static + { + $this->isModalClosedByHittingEscape = $condition; + + return $this; + } + /** * @deprecated Use `modalAlignment(Alignment::Center)` instead. */ @@ -600,6 +608,11 @@ trait CanOpenModal return (bool) ($this->evaluate($this->isModalClosedByClickingAway) ?? Modal::$isClosedByClickingAway); } + public function isModalClosedByHittingEscape(): bool + { + return (bool) ($this->evaluate($this->isModalClosedByHittingEscape) ?? Modal::$isClosedByHittingEscape); + } + /** * @deprecated Use `makeModalSubmitAction()` instead. * diff --git a/packages/support/resources/views/components/modal/index.blade.php b/packages/support/resources/views/components/modal/index.blade.php index 6a3cc6a1e2..14682c1389 100644 --- a/packages/support/resources/views/components/modal/index.blade.php +++ b/packages/support/resources/views/components/modal/index.blade.php @@ -8,6 +8,7 @@ 'ariaLabelledby' => null, 'closeButton' => \Filament\Support\View\Components\Modal::$hasCloseButton, 'closeByClickingAway' => \Filament\Support\View\Components\Modal::$isClosedByClickingAway, + 'closeByHittingEscape' => \Filament\Support\View\Components\Modal::$isClosedByHittingEscape, 'closeEventName' => 'close-modal', 'description' => null, 'displayClasses' => 'inline-block', @@ -23,6 +24,7 @@ 'id' => null, 'openEventName' => 'open-modal', 'slideOver' => false, + 'closeToAction' => true, 'stickyFooter' => false, 'stickyHeader' => false, 'trigger' => null, @@ -155,7 +157,10 @@ $watch('isOpen', () => (isShown = isOpen)) }) " - x-on:keydown.window.escape="{{ $closeEventHandler }}" + @if ($closeByHittingEscape) + x-on:keydown.window.escape="{{ $closeEventHandler }}" + @endif + x-show="isShown" x-transition:enter="duration-300" x-transition:leave="duration-300" @@ -175,9 +180,10 @@ ($extraModalWindowAttributeBag ?? new \Illuminate\View\ComponentAttributeBag())->class([ 'fi-modal-window pointer-events-auto relative row-start-2 flex w-full cursor-default flex-col bg-white shadow-xl ring-1 ring-gray-950/5 dark:bg-gray-900 dark:ring-white/10', 'fi-modal-slide-over-window ms-auto overflow-y-auto' => $slideOver, + 'p-10 border border-red-300 shadow shadow-4xl' => $closeToAction, // Using an arbitrary value instead of the h-dvh class that was added in Tailwind CSS v3.4.0 // to ensure compatibility with custom themes that may use an older version of Tailwind CSS. - 'h-[100dvh]' => $slideOver || ($width === MaxWidth::Screen), + 'h-[100dvh]' => ($slideOver || ($width === MaxWidth::Screen)) && !$closeToAction, 'mx-auto rounded-xl' => ! ($slideOver || ($width === MaxWidth::Screen)), 'hidden' => ! $visible, match ($width) { diff --git a/packages/support/src/View/Components/Modal.php b/packages/support/src/View/Components/Modal.php index 9b90598807..3127febf18 100644 --- a/packages/support/src/View/Components/Modal.php +++ b/packages/support/src/View/Components/Modal.php @@ -7,6 +7,7 @@ class Modal public static bool $hasCloseButton = true; public static bool $isClosedByClickingAway = true; + public static bool $isClosedByHittingEscape = true; public static function closeButton(bool $condition = true): void { @@ -17,4 +18,9 @@ class Modal { static::$isClosedByClickingAway = $condition; } + + public static function closedByHittingEscape(bool $condition = true): void + { + static::$isClosedByHittingEscape = $condition; + } }