Skip to content

Modal Flyout version #1

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 2 commits into from
Apr 8, 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
27 changes: 25 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +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/resources/views/**/*.blade.php';
@source '../../vendor/cloudstudio/laravel-livewire-modal/src/Services/ModalConfigService.php';
@source '../../vendor/cloudstudio/laravel-livewire-modal/dist/modal.css';
```

Then run:
Expand Down Expand Up @@ -164,6 +163,30 @@ public static function modalMaxWidth(): string
}
```

### Display as Flyout

To display the modal as a flyout:

```php
public static function modalFlyout(): bool
{
return true;
}
```

### Flyout Position

To change the position of the flyout.
Available positions are `right`, `left`, and `bottom`.
Default is `right`:

```php
public static function modalFlyoutPosition(): string
{
return 'left';
}
```

### Disable Closing on Escape Key

To prevent the modal from closing when the escape key is pressed:
Expand Down
7 changes: 7 additions & 0 deletions config/livewire-modal.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,17 @@
|
| Supported modal_max_width
| 'sm', 'md', 'lg', 'xl', '2xl', '3xl', '4xl', '5xl', '6xl', '7xl'
|
| Supported flyout_position
| 'right', 'left', 'bottom'
*/
'component_defaults' => [
'modal_max_width' => '2xl',

'display_as_flyout' => false,

'flyout_position' => 'right',

'close_modal_on_click_away' => true,

'close_modal_on_escape' => true,
Expand Down
1 change: 1 addition & 0 deletions dist/modal.css

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion dist/modal.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"private": true,
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build"
Expand Down
13 changes: 13 additions & 0 deletions resources/css/modal.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
@source '../resources/views/*.blade.php';

/* Max Widths Classes */
@source inline("sm:max-w-sm");
@source inline("sm:max-w-md");
@source inline("md:max-w-lg");
@source inline("md:max-w-xl");
@source inline("lg:max-w-2xl");
@source inline("lg:max-w-3xl");
@source inline("xl:max-w-4xl");
@source inline("xl:max-w-5xl");
@source inline("2xl:max-w-6xl");
@source inline("2xl:max-w-7xl");
8 changes: 7 additions & 1 deletion resources/js/modal.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ window.LivewireUIModal = () => {
activeComponent: false,
componentHistory: [],
modalWidth: null,
modalFlyout: false,
modalFlyoutPosition: 'right',
listeners: [],

init() {
Expand Down Expand Up @@ -144,6 +146,8 @@ window.LivewireUIModal = () => {
this.activeComponent = id
this.showActiveComponent = true;
this.modalWidth = this.getActiveComponentModalAttribute('maxWidthClass');
this.modalFlyout = this.getActiveComponentModalAttribute('modalFlyout');
this.modalFlyoutPosition = this.getActiveComponentModalAttribute('modalFlyoutPosition');
} else {
this.showActiveComponent = false;

Expand All @@ -153,6 +157,8 @@ window.LivewireUIModal = () => {
this.activeComponent = id;
this.showActiveComponent = true;
this.modalWidth = this.getActiveComponentModalAttribute('maxWidthClass');
this.modalFlyout = this.getActiveComponentModalAttribute('displayAsFlyout');
this.modalFlyoutPosition = this.getActiveComponentModalAttribute('flyoutPosition');
}, 300);
}

Expand Down Expand Up @@ -216,4 +222,4 @@ window.LivewireUIModal = () => {
}
}
};
}
}
62 changes: 53 additions & 9 deletions resources/views/modal.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,60 @@

<span class="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true">&#8203;</span>

<div x-show="show && showActiveComponent" 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.inert="show && showActiveComponent" aria-modal="true">
{{-- 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')
</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, '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']"
id="modal-container-right" x-trap.noscroll="show && showActiveComponent && modalFlyout && modalFlyoutPosition === 'right'" aria-modal="true">
@include('laravel-livewire-modal::modal-content')
</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, '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']"
id="modal-container-left" x-trap.noscroll="show && showActiveComponent && modalFlyout && modalFlyoutPosition === 'left'" aria-modal="true">
@include('laravel-livewire-modal::modal-content')
</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, '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']"
id="modal-container-bottom" x-trap.noscroll="show && showActiveComponent && modalFlyout && modalFlyoutPosition === 'bottom'" aria-modal="true">
@include('laravel-livewire-modal::modal-content')
</div>
</div>
Expand Down
20 changes: 20 additions & 0 deletions src/LivewireModal.php
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,26 @@ public static function modalMaxWidthClass(): string
return app(ModalConfigService::class)->getModalMaxWidthClass(static::modalMaxWidth());
}

/**
* Get the modal variant.
*
* @return string
*/
public static function modalFlyout(): bool
{
return app(ModalConfigService::class)->shouldDisplayAsFlyout();
}

/**
* Get the modal flyout position.
*
* @return string
*/
public static function modalFlyoutPosition(): string
{
return app(ModalConfigService::class)->getFlyoutPosition();
}

/**
* Check if modal should close on click away.
*/
Expand Down
20 changes: 20 additions & 0 deletions src/Services/ModalConfigService.php
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,26 @@ public function getAvailableMaxWidths(): array
return static::$maxWidths;
}

/**
* Check if modal should be displayed as a flyout.
*
* @return bool Whether to display modal as a flyout
*/
public function shouldDisplayAsFlyout(): bool
{
return config('livewire-modal.component_defaults.display_as_flyout', false);
}

/**
* Get the flyout position.
*
* @return string The flyout position
*/
public function getFlyoutPosition(): string
{
return config('livewire-modal.component_defaults.flyout_position', 'right');
}

/**
* Check if modal should close on click away.
*
Expand Down
31 changes: 30 additions & 1 deletion tests/LivewireModalTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,27 @@ public function render()
}
}

// Test modal component with custom flyout configuration
class FlyoutModalComponent extends LivewireModal
{
public static function modalFlyout(): bool
{
return true;
}

public static function modalFlyoutPosition(): string
{
return 'right';
}

public function render()
{
return <<<'blade'
<div>Flyout config modal</div>
blade;
}
}

// Test the default configuration methods
it('has default configuration values', function () {
$defaultConfig = app(ModalConfigService::class);
Expand All @@ -88,7 +109,9 @@ public function render()
->and(EventModalComponent::closeModalOnEscape())->toBe($defaultConfig->shouldCloseModalOnEscape())
->and(EventModalComponent::closeModalOnEscapeIsForceful())->toBe($defaultConfig->isCloseModalOnEscapeForceful())
->and(EventModalComponent::dispatchCloseEvent())->toBe($defaultConfig->shouldDispatchCloseEvent())
->and(EventModalComponent::destroyOnClose())->toBe($defaultConfig->shouldDestroyOnClose());
->and(EventModalComponent::destroyOnClose())->toBe($defaultConfig->shouldDestroyOnClose())
->and(EventModalComponent::modalFlyout())->toBe($defaultConfig->shouldDisplayAsFlyout())
->and(EventModalComponent::modalFlyoutPosition())->toBe($defaultConfig->getFlyoutPosition());
});

// Test modal max width class
Expand All @@ -109,6 +132,12 @@ public function render()
->and(CustomConfigModalComponent::destroyOnClose())->toBeTrue();
});

// Test custom flyout configuration
it('can override flyout configuration', function () {
expect(FlyoutModalComponent::modalFlyout())->toBeTrue()
->and(FlyoutModalComponent::modalFlyoutPosition())->toBe('right');
});

// Test skipPreviousModal method
it('can skip previous modals', function () {
$component = new EventModalComponent;
Expand Down
Loading