Skip to content

Fix double mounted components #5

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

Merged
merged 1 commit into from
Apr 14, 2025
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
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ After installing the package, you need to include the modal component in your bl
To properly configure Tailwind 4 with this package, add these lines to your `app.css` file:

```css
@source '../../vendor/cloudstudio/laravel-livewire-modal/dist/modal.css';
@import '../../vendor/cloudstudio/laravel-livewire-modal/dist/modal.css';
```

Then run:
Expand Down Expand Up @@ -313,6 +313,8 @@ return [
*/
'component_defaults' => [
'modal_max_width' => '2xl',
'display_as_flyout' => false,
'flyout_position' => 'right',
'close_modal_on_click_away' => true,
'close_modal_on_escape' => true,
'close_modal_on_escape_is_forceful' => true,
Expand Down
96 changes: 50 additions & 46 deletions resources/views/modal.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,69 +18,73 @@
<span class="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true">&#8203;</span>

{{-- Default Modal --}}
<div x-show="show && showActiveComponent && !modalFlyout"
x-transition:enter="ease-out duration-300"
x-transition:enter-start="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
x-transition:enter-end="opacity-100 translate-y-0 sm:scale-100"
x-transition:leave="ease-in duration-200"
x-transition:leave-start="opacity-100 translate-y-0 sm:scale-100"
x-transition:leave-end="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
x-bind:class="modalWidth"
class="inline-block w-full align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:w-full "
id="modal-container" x-trap.noscroll="show && showActiveComponent && !modalFlyout" aria-modal="true">
@include('laravel-livewire-modal::modal-content', [
'modalFlyout' => false
])
<div wire:ignore.self
x-show="show && showActiveComponent && !modalFlyout"
x-transition:enter="ease-out duration-300"
x-transition:enter-start="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
x-transition:enter-end="opacity-100 translate-y-0 sm:scale-100"
x-transition:leave="ease-in duration-200"
x-transition:leave-start="opacity-100 translate-y-0 sm:scale-100"
x-transition:leave-end="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
x-bind:class="modalWidth"
class="inline-block w-full align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:w-full "
id="modal-container" x-trap.noscroll="show && showActiveComponent && !modalFlyout" aria-modal="true">
@include('laravel-livewire-modal::modal-content', [
'modalFlyout' => false
])
</div>

{{-- Flyout Right --}}
<div x-show="show && showActiveComponent && modalFlyout && modalFlyoutPosition === 'right'"
x-transition:enter="transform transition ease-in-out duration-300"
x-transition:enter-start="translate-x-full"
x-transition:enter-end="translate-x-0"
x-transition:leave="transform transition ease-in-out duration-300"
x-transition:leave-start="translate-x-0"
x-transition:leave-end="translate-x-full"
x-bind:class="modalWidth"
class="fixed h-full md:w-[25rem] top-0 right-0 border-s overflow-y-auto overflow-x-hidden
z-50 shadow-2xl modal-flyout-right bg-white dark:bg-zinc-800 border-zinc-200 dark:border-zinc-700 transform transition-all text-left"
id="modal-container-right" x-trap.noscroll="show && showActiveComponent && modalFlyout && modalFlyoutPosition === 'right'" aria-modal="true">
<div wire:ignore.self
x-show="show && showActiveComponent && modalFlyout && modalFlyoutPosition === 'right'"
x-transition:enter="transform transition ease-in-out duration-300"
x-transition:enter-start="translate-x-full"
x-transition:enter-end="translate-x-0"
x-transition:leave="transform transition ease-in-out duration-300"
x-transition:leave-start="translate-x-0"
x-transition:leave-end="translate-x-full"
x-bind:class="modalWidth"
class="fixed h-full md:w-[25rem] top-0 right-0 border-s overflow-y-auto overflow-x-hidden
z-50 shadow-2xl modal-flyout-right bg-white dark:bg-zinc-800 border-zinc-200 dark:border-zinc-700 transform transition-all text-left"
id="modal-container-right" x-trap.noscroll="show && showActiveComponent && modalFlyout && modalFlyoutPosition === 'right'" aria-modal="true">
@include('laravel-livewire-modal::modal-content', [
'modalFlyout' => true,
'modalFlyoutPosition' => 'right'
])
</div>

{{-- Flyout Left --}}
<div x-show="show && showActiveComponent && modalFlyout && modalFlyoutPosition === 'left'"
x-transition:enter="transform transition ease-in-out duration-300"
x-transition:enter-start="-translate-x-full"
x-transition:enter-end="translate-x-0"
x-transition:leave="transform transition ease-in-out duration-300"
x-transition:leave-start="translate-x-0"
x-transition:leave-end="-translate-x-full"
x-bind:class="modalWidth"
class="fixed h-full md:w-[25rem] top-0 left-0 border-e overflow-y-auto overflow-x-hidden
z-50 shadow-2xl modal-flyout-left bg-white dark:bg-zinc-800 border-zinc-200 dark:border-zinc-700 transform transition-all text-left"
id="modal-container-left" x-trap.noscroll="show && showActiveComponent && modalFlyout && modalFlyoutPosition === 'left'" aria-modal="true">
<div wire:ignore.self
x-show="show && showActiveComponent && modalFlyout && modalFlyoutPosition === 'left'"
x-transition:enter="transform transition ease-in-out duration-300"
x-transition:enter-start="-translate-x-full"
x-transition:enter-end="translate-x-0"
x-transition:leave="transform transition ease-in-out duration-300"
x-transition:leave-start="translate-x-0"
x-transition:leave-end="-translate-x-full"
x-bind:class="modalWidth"
class="fixed h-full md:w-[25rem] top-0 left-0 border-e overflow-y-auto overflow-x-hidden
z-50 shadow-2xl modal-flyout-left bg-white dark:bg-zinc-800 border-zinc-200 dark:border-zinc-700 transform transition-all text-left"
id="modal-container-left" x-trap.noscroll="show && showActiveComponent && modalFlyout && modalFlyoutPosition === 'left'" aria-modal="true">
@include('laravel-livewire-modal::modal-content', [
'modalFlyout' => true,
'modalFlyoutPosition' => 'left'
])
</div>

{{-- Flyout Bottom --}}
<div x-show="show && showActiveComponent && modalFlyout && modalFlyoutPosition === 'bottom'"
x-transition:enter="transform transition ease-in-out duration-300"
x-transition:enter-start="translate-y-full"
x-transition:enter-end="translate-y-0"
x-transition:leave="transform transition ease-in-out duration-300"
x-transition:leave-start="translate-y-0"
x-transition:leave-end="translate-y-full"
x-bind:class="modalWidth"
class="fixed min-h-[25rem] w-screen min-w-[100vw] bottom-0 left-0 right-0 border-t overflow-y-auto overflow-x-hidden
z-50 shadow-2xl modal-flyout-bottom bg-white dark:bg-zinc-800 border-zinc-200 dark:border-zinc-700 transform transition-all text-left"
id="modal-container-bottom" x-trap.noscroll="show && showActiveComponent && modalFlyout && modalFlyoutPosition === 'bottom'" aria-modal="true">
<div wire:ignore.self
x-show="show && showActiveComponent && modalFlyout && modalFlyoutPosition === 'bottom'"
x-transition:enter="transform transition ease-in-out duration-300"
x-transition:enter-start="translate-y-full"
x-transition:enter-end="translate-y-0"
x-transition:leave="transform transition ease-in-out duration-300"
x-transition:leave-start="translate-y-0"
x-transition:leave-end="translate-y-full"
x-bind:class="modalWidth"
class="fixed min-h-[25rem] w-screen min-w-[100vw] bottom-0 left-0 right-0 border-t overflow-y-auto overflow-x-hidden
z-50 shadow-2xl modal-flyout-bottom bg-white dark:bg-zinc-800 border-zinc-200 dark:border-zinc-700 transform transition-all text-left"
id="modal-container-bottom" x-trap.noscroll="show && showActiveComponent && modalFlyout && modalFlyoutPosition === 'bottom'" aria-modal="true">
@include('laravel-livewire-modal::modal-content', [
'modalFlyout' => true,
'modalFlyoutPosition' => 'bottom'
Expand Down
50 changes: 38 additions & 12 deletions src/ModalContainer.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,29 @@ class ModalContainer extends Component
{
/**
* The active component ID.
*
* @var string|null
*/
public ?string $activeComponent = null;

/**
* The components array.
*
* @var array
*/
public array $components = [];

/**
* The modal manager service.
*
* @var \Cloudstudio\Modal\Services\ModalManagerService|null
*/
protected ?ModalManagerService $managerService = null;

/**
* Get the modal manager service.
*
* @return \Cloudstudio\Modal\Services\ModalManagerService
*/
protected function managerService(): ModalManagerService
{
Expand All @@ -39,6 +47,8 @@ protected function managerService(): ModalManagerService

/**
* Reset the state.
*
* @return void
*/
public function resetState(): void
{
Expand All @@ -52,6 +62,7 @@ public function resetState(): void
* @param string $component The component name
* @param array $arguments The component arguments
* @param array $modalAttributes Additional modal attributes
* @return void
*/
public function openModal(string $component, array $arguments = [], array $modalAttributes = []): void
{
Expand All @@ -67,6 +78,7 @@ public function openModal(string $component, array $arguments = [], array $modal
* Destroy a component.
*
* @param string $id The component ID
* @return void
*/
public function destroyComponent(string $id): void
{
Expand All @@ -75,6 +87,8 @@ public function destroyComponent(string $id): void

/**
* Get the listeners.
*
* @return array<string, string>
*/
public function getListeners(): array
{
Expand All @@ -86,31 +100,43 @@ public function getListeners(): array

/**
* Should show modal.
* Checks if a modal component should be displayed based on its attributes and the container's state.
*
* @param array $componentAttributes The component attributes
* @param bool $modalFlyout Whether the modal is a flyout
* @param string|null $modalFlyoutPosition The modal flyout position
* @return bool Whether the modal should be shown
* @param array<string, mixed> $componentAttributes The component attributes
* @param bool $modalFlyout Whether the container rendering this component is a flyout.
* @param string|null $modalFlyoutPosition The position of the flyout container ('right', 'left', 'bottom').
* @return bool Whether the modal should be shown.
*/
public function shouldShowModal(array $componentAttributes, bool $modalFlyout, ?string $modalFlyoutPosition = null): bool
{
// Si no es un flyout, verifica que el componente tampoco lo sea
if (!$modalFlyout) {
return !($componentAttributes['modalFlyout'] ?? false);
$isComponentFlyout = $componentAttributes['modalFlyout'] ?? false;
$componentFlyoutPosition = $componentAttributes['modalFlyoutPosition'] ?? null;

// Case 1: Standard Modal Container
// If the container is NOT a flyout, show the component only if it's also NOT a flyout.
if (! $modalFlyout) {
return ! $isComponentFlyout;
}

$attributesFlyoutPosition = $componentAttributes['modalFlyoutPosition'] ?? null;
// Case 2: Flyout Container
// If the container IS a flyout, show the component only if:
// 1. The component itself IS ALSO a flyout.
// 2. Their positions match.
if (! $isComponentFlyout) {
return false; // Component is not a flyout, so don't show it in a flyout container.
}

// Both container and component are flyouts, check positions.
return match ($modalFlyoutPosition) {
'right' => $attributesFlyoutPosition === $modalFlyoutPosition,
'left' => $attributesFlyoutPosition === $modalFlyoutPosition,
'bottom' => $attributesFlyoutPosition === $modalFlyoutPosition,
default => false,
'right', 'left', 'bottom' => $componentFlyoutPosition === $modalFlyoutPosition,
default => false, // Invalid or no position specified for the container.
};
}

/**
* Render the modal container.
*
* @return \Illuminate\View\View
*/
public function render(): \Illuminate\View\View
{
Expand Down