Skip to content

Commit

Permalink
Add option to destroy modal state (#95)
Browse files Browse the repository at this point in the history
  • Loading branch information
thermiteplasma authored Nov 5, 2021
1 parent 51801f2 commit b3e08a9
Show file tree
Hide file tree
Showing 9 changed files with 98 additions and 14 deletions.
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,14 @@ By default, the modal will close when you click outside the modal. If you want t
}
```

By default, when a child modal is closed, the closed components state is still available if the same modal component is opened again. If you would like to destroy the component when its closed you can override the static `destroyOnClose` method and have it return `true`. When a destroyed modal is opened again its state will be reset.
```php
public static function destroyOnClose(): bool
{
return true;
}
```

## Skipping previous modals
In some cases you might want to skip previous modals. For example:
1. Team overview modal
Expand Down Expand Up @@ -314,6 +322,12 @@ class DeleteTeam extends ModalComponent
}
```

You can also optionally call the `destroySkippedModals()` method to destroy the skipped modals so if any are opened again their state will be reset





## Building Tailwind CSS for production
To purge the classes used by the package, add the following lines to your purge array in `tailwind.config.js`:
```js
Expand Down Expand Up @@ -406,6 +420,8 @@ return [
'close_modal_on_escape_is_forceful' => true,

'dispatch_close_event' => false,

'destroy_on_close' => false,
],
];
```
Expand Down
2 changes: 2 additions & 0 deletions config/livewire-ui-modal.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,5 +48,7 @@
'close_modal_on_escape_is_forceful' => true,

'dispatch_close_event' => false,

'destroy_on_close' => false,
],
];
2 changes: 1 addition & 1 deletion public/modal.js

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

16 changes: 13 additions & 3 deletions resources/js/modal.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,23 @@ window.LivewireUIModal = () => {

this.closeModal(true);
},
closeModal(force = false, skipPreviousModals = 0) {
closeModal(force = false, skipPreviousModals = 0, destroySkipped = false) {

if (this.getActiveComponentModalAttribute('dispatchCloseEvent') === true) {
const componentName = this.$wire.get('components')[this.activeComponent].name;
Livewire.emit('modalClosed', componentName);
}

if (this.getActiveComponentModalAttribute('destroyOnClose') === true) {
Livewire.emit('destroyComponent', this.activeComponent);
}

if (skipPreviousModals > 0) {
for (var i = 0; i < skipPreviousModals; i++) {
if (destroySkipped) {
const id = this.componentHistory[this.componentHistory.length - 1];
Livewire.emit('destroyComponent', id);
}
this.componentHistory.pop();
}
}
Expand Down Expand Up @@ -126,13 +134,15 @@ window.LivewireUIModal = () => {
}
});

Livewire.on('closeModal', (force = false, skipPreviousModals = 0) => {
this.closeModal(force, skipPreviousModals);
Livewire.on('closeModal', (force = false, skipPreviousModals = 0, destroySkipped = false) => {
this.closeModal(force, skipPreviousModals, destroySkipped);
});

Livewire.on('activeModalComponentChanged', (id) => {
this.setActiveModalComponent(id);
});


}
};
}
2 changes: 1 addition & 1 deletion resources/views/modal.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ class="fixed inset-0 transition-all transform"
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"
>
@forelse($components as $id => $component)
<div x-show.immediate="activeComponent == '{{ $id }}'" x-ref="{{ $id }}">
<div x-show.immediate="activeComponent == '{{ $id }}'" x-ref="{{ $id }}" wire:key="{{ $id }}">
@livewire($component['name'], $component['attributes'], key($id))
</div>
@empty
Expand Down
7 changes: 7 additions & 0 deletions src/Modal.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ public function openModal($component, $componentAttributes = [], $modalAttribute
'closeOnEscape' => $componentClass::closeModalOnEscape(),
'closeOnEscapeIsForceful' => $componentClass::closeModalOnEscapeIsForceful(),
'dispatchCloseEvent' => $componentClass::dispatchCloseEvent(),
'destroyOnClose' => $componentClass::destroyOnClose(),
'maxWidth' => $componentClass::modalMaxWidth(),
], $modalAttributes),
];
Expand All @@ -47,10 +48,16 @@ public function openModal($component, $componentAttributes = [], $modalAttribute
$this->emit('activeModalComponentChanged', $id);
}

public function destroyComponent($id): void
{
unset($this->components[$id]);
}

public function getListeners(): array
{
return [
'openModal',
'destroyComponent'
];
}

Expand Down
23 changes: 19 additions & 4 deletions src/ModalComponent.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,26 @@ abstract class ModalComponent extends Component implements Contract

public int $skipModals = 0;

public function skipPreviousModals($count = 1): self
public bool $destroySkipped = false;

public function destroySkippedModals(): self
{
$this->destroySkipped = true;

return $this;
}

public function skipPreviousModals($count = 1, $destroy = false): self
{
$this->skipPreviousModal($count);
$this->skipPreviousModal($count, $destroy);

return $this;
}

public function skipPreviousModal($count = 1): self
public function skipPreviousModal($count = 1, $destroy = false): self
{
$this->skipModals = $count;
$this->destroySkipped = $destroy;

return $this;
}
Expand All @@ -34,7 +44,7 @@ public function forceClose(): self

public function closeModal(): void
{
$this->emit('closeModal', $this->forceClose, $this->skipModals);
$this->emit('closeModal', $this->forceClose, $this->skipModals, $this->destroySkipped);
}

public function closeModalWithEvents(array $events): void
Expand Down Expand Up @@ -68,6 +78,11 @@ public static function dispatchCloseEvent(): bool
return config('livewire-ui-modal.component_defaults.dispatch_close_event', false);
}

public static function destroyOnClose(): bool
{
return config('livewire-ui-modal.component_defaults.destroy_on_close', false);
}

private function emitModalEvents(array $events): void
{
foreach ($events as $component => $event) {
Expand Down
14 changes: 10 additions & 4 deletions tests/LivewireModalComponentTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,28 +11,34 @@ public function testCloseModal(): void
{
Livewire::test(DemoModal::class)
->call('closeModal')
->assertEmitted('closeModal', false, 0);
->assertEmitted('closeModal', false, 0, false);
}

public function testForceCloseModal(): void
{
Livewire::test(DemoModal::class)
->call('forceClose')
->call('closeModal')
->assertEmitted('closeModal', true, 0);
->assertEmitted('closeModal', true, 0, false);
}

public function testModalSkipping(): void
{
Livewire::test(DemoModal::class)
->call('skipPreviousModals', 5)
->call('closeModal')
->assertEmitted('closeModal', false, 5);
->assertEmitted('closeModal', false, 5, false);

Livewire::test(DemoModal::class)
->call('skipPreviousModal')
->call('closeModal')
->assertEmitted('closeModal', false, 1);
->assertEmitted('closeModal', false, 1, false);

Livewire::test(DemoModal::class)
->call('skipPreviousModal')
->call('destroySkippedModals')
->call('closeModal')
->assertEmitted('closeModal', false, 1, true);
}

public function testModalEventEmitting(): void
Expand Down
30 changes: 29 additions & 1 deletion tests/LivewireModalTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
use LivewireUI\Modal\Tests\Components\DemoModal;
use LivewireUI\Modal\Tests\Components\InvalidModal;

use function PHPUnit\Framework\assertArrayNotHasKey;

class LivewireModalTest extends TestCase
{
public function testOpenModalEventListener(): void
Expand All @@ -17,7 +19,7 @@ public function testOpenModalEventListener(): void
// Event attributes
$component = 'demo-modal';
$componentAttributes = ['message' => 'Foobar'];
$modalAttributes = ['hello' => 'world', 'closeOnEscape' => true, 'maxWidth' => '2xl', 'closeOnClickAway' => true, 'closeOnEscapeIsForceful' => true, 'dispatchCloseEvent' => false];
$modalAttributes = ['hello' => 'world', 'closeOnEscape' => true, 'maxWidth' => '2xl', 'closeOnClickAway' => true, 'closeOnEscapeIsForceful' => true, 'dispatchCloseEvent' => false, 'destroyOnClose' => false];

// Demo modal unique identifier
$id = md5($component . serialize($componentAttributes));
Expand All @@ -38,6 +40,32 @@ public function testOpenModalEventListener(): void
->assertEmitted('activeModalComponentChanged', $id);
}

public function testDestroyComponentEventListener(): void
{
// Demo modal component
Livewire::component('demo-modal', DemoModal::class);

$component = 'demo-modal';
$componentAttributes = ['message' => 'Foobar'];
$modalAttributes = ['hello' => 'world', 'closeOnEscape' => true, 'maxWidth' => '2xl', 'closeOnClickAway' => true, 'closeOnEscapeIsForceful' => true, 'dispatchCloseEvent' => false, 'destroyOnClose' => false];

// Demo modal unique identifier
$id = md5($component . serialize($componentAttributes));

Livewire::test(Modal::class)
->emit('openModal', $component, $componentAttributes, $modalAttributes)
->assertSet('components', [
$id => [
'name' => $component,
'attributes' => $componentAttributes,
'modalAttributes' => $modalAttributes,
],
])
->emit('destroyComponent', $id)
->assertSet('components', []);

}

public function testModalReset(): void
{
Livewire::component('demo-modal', DemoModal::class);
Expand Down

0 comments on commit b3e08a9

Please sign in to comment.