-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add components for modals and buttons opening a modal (#17)
* Add components for modals and buttons opening a modal * Fix PHPDoc comments and formatting
- Loading branch information
1 parent
4114892
commit 779ef41
Showing
6 changed files
with
335 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
@props([ | ||
'modal', | ||
]) | ||
@php | ||
/** @var string $modal */ | ||
/** @var \Illuminate\View\ComponentAttributeBag $attributes */ | ||
@endphp | ||
<x-bs::button :attributes="$attributes | ||
->merge([ | ||
'type' => 'button', | ||
'data-bs-toggle' => 'modal', | ||
'data-bs-target' => '#' . $modal, | ||
])">{{ $slot }}</x-bs::button> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
@props([ | ||
'id', | ||
'centered' => false, | ||
'fade' => true, | ||
'fullScreen' => false, | ||
'scrollable' => false, | ||
'staticBackdrop' => false, | ||
'closeButton' => true, | ||
'closeButtonTitle' => 'Close', | ||
]) | ||
@php | ||
/** @var string $id */ | ||
$labelId = $id . 'Label'; | ||
/** @var bool $centered */ | ||
/** @var bool $fade */ | ||
/** @var bool|string $fullScreen */ | ||
/** @var bool $scrollable */ | ||
/** @var bool $staticBackdrop */ | ||
/** @var string|bool $closeButton */ | ||
$closeButton = $closeButton === true ? 'secondary' : $closeButton; | ||
$showCloseButtonInFooter = is_string($closeButton); | ||
/** @var string $closeButtonTitle */ | ||
/** @var \Illuminate\View\ComponentAttributeBag $attributes */ | ||
/** @var ?\Illuminate\View\ComponentSlot $title */ | ||
/** @var ?\Illuminate\View\ComponentSlot $footer */ | ||
@endphp | ||
<div {{ $attributes | ||
->class([ | ||
'modal', | ||
'fade' => $fade, | ||
]) | ||
->merge([ | ||
'id' => $id, | ||
'tabindex' => -1, | ||
'aria-labelledby' => $id . 'Label', | ||
'aria-hidden' => 'true', | ||
'data-bs-backdrop' => $staticBackdrop ? 'static' : null, | ||
'data-bs-keyboard' => $staticBackdrop ? 'false' : null, | ||
])}}> | ||
<div @class([ | ||
'modal-dialog', | ||
'modal-fullscreen' => $fullScreen === true, | ||
'modal-fullscreen-' . $fullScreen . '-down' => is_string($fullScreen), | ||
'modal-dialog-centered' => $centered, | ||
'modal-dialog-scrollable' => $scrollable, | ||
])> | ||
<div class="modal-content"> | ||
<div class="modal-header"> | ||
@if(isset($title) && $title instanceof \Illuminate\View\ComponentSlot) | ||
@php | ||
$container = $title->attributes->get('container', 'h1'); | ||
@endphp | ||
<{{ $container }} {{ $title->attributes | ||
->except([ | ||
'container', | ||
]) | ||
->class([ | ||
'modal-title', | ||
]) | ||
->merge([ | ||
'id' => $labelId, | ||
]) }}>{{ $title }}</{{ $container }}> | ||
@endif | ||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="{{ $closeButtonTitle }}"></button> | ||
</div> | ||
<div class="modal-body">{{ $slot }}</div> | ||
@if($showCloseButtonInFooter || (isset($footer) && $footer instanceof \Illuminate\View\ComponentSlot)) | ||
@php | ||
$footer = $footer ?? new \Illuminate\View\ComponentSlot(); | ||
@endphp | ||
<div {{ $footer->attributes | ||
->class([ | ||
'modal-footer', | ||
]) }}> | ||
@if($showCloseButtonInFooter) | ||
<x-bs::button :variant="$closeButton" {{ $attributes | ||
->merge([ | ||
'type' => 'button', | ||
'data-bs-dismiss' => 'modal', | ||
]) }}>{{ $closeButtonTitle }}</x-bs::button> | ||
@endif{{-- | ||
--}}{{ $footer }}</div> | ||
@endif | ||
</div> | ||
</div> | ||
</div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
<?php | ||
|
||
namespace Feature\Modal; | ||
|
||
use Portavice\Bladestrap\Tests\Feature\ComponentTestCase; | ||
use Portavice\Bladestrap\Tests\Traits\TestsVariants; | ||
|
||
class ModalButtonTest extends ComponentTestCase | ||
{ | ||
use TestsVariants; | ||
|
||
/** | ||
* @dataProvider variants | ||
*/ | ||
public function testModalButtonRendersCorrectly(string $buttonClass, ?string $variant): void | ||
{ | ||
$this->assertBladeRendersToHtml( | ||
'<button class="btn ' . $buttonClass . '" type="button" data-bs-toggle="modal" data-bs-target="#my-modal">Open modal</button>', | ||
sprintf( | ||
'<x-bs::modal.button %s modal="my-modal">Open modal</x-bs::modal.button>', | ||
self::makeVariantAttribute($variant) | ||
) | ||
); | ||
} | ||
|
||
public static function variants(): array | ||
{ | ||
return [ | ||
['btn-primary', null], | ||
...self::makeDataProvider('btn-'), | ||
]; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,174 @@ | ||
<?php | ||
|
||
namespace Feature\Modal; | ||
|
||
use Portavice\Bladestrap\Tests\Feature\ComponentTestCase; | ||
|
||
class ModalTest extends ComponentTestCase | ||
{ | ||
/** | ||
* @dataProvider modalOptions | ||
*/ | ||
public function testModalRendersOptionsCorrectly(string $blade, string $modalAttributes, string $modalDialogClasses): void | ||
{ | ||
$this->assertBladeRendersToHtml( | ||
'<div id="exampleModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true" ' . $modalAttributes . '> | ||
<div class="' . $modalDialogClasses . '"> | ||
<div class="modal-content"> | ||
<div class="modal-header"> | ||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> | ||
</div> | ||
<div class="modal-body">My modal</div> | ||
<div class="modal-footer"> | ||
<button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Close</button> | ||
</div> | ||
</div> | ||
</div> | ||
</div>', | ||
$this->bladeView('<x-bs::modal id="exampleModal" ' . $blade .'>My modal</x-bs::modal>') | ||
); | ||
} | ||
|
||
public static function modalOptions(): array | ||
{ | ||
return [ | ||
['', 'class="modal fade"', 'modal-dialog'], | ||
[':centered="true"', 'class="modal fade"', 'modal-dialog modal-dialog-centered'], | ||
[':centered="true" :scrollable="true"', 'class="modal fade"', 'modal-dialog modal-dialog-centered modal-dialog-scrollable'], | ||
[':fade="false"', 'class="modal"', 'modal-dialog'], | ||
[':scrollable="true"', 'class="modal fade"', 'modal-dialog modal-dialog-scrollable'], | ||
[':static-backdrop="true"', 'data-bs-backdrop="static" data-bs-keyboard="false" class="modal fade"', 'modal-dialog'], | ||
]; | ||
} | ||
|
||
/** | ||
* @dataProvider fullScreenOptions | ||
*/ | ||
public function testModalRendersFullScreenOptionsCorrectly(bool|string $fullScreen, string $modalDialogClass): void | ||
{ | ||
$this->assertBladeRendersToHtml( | ||
'<div id="exampleModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true" class="modal fade"> | ||
<div class="modal-dialog ' . $modalDialogClass . '"> | ||
<div class="modal-content"> | ||
<div class="modal-header"> | ||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> | ||
</div> | ||
<div class="modal-body">My modal</div> | ||
<div class="modal-footer"> | ||
<button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Close</button> | ||
</div> | ||
</div> | ||
</div> | ||
</div>', | ||
$this->bladeView('<x-bs::modal id="exampleModal" ' . $fullScreen .'>My modal</x-bs::modal>') | ||
); | ||
} | ||
|
||
public static function fullScreenOptions(): array | ||
{ | ||
return [ | ||
['', ''], | ||
[':full-screen="false"', ''], | ||
[':full-screen="true"', 'modal-fullscreen'], | ||
['full-screen="sm"', 'modal-fullscreen-sm-down'], | ||
['full-screen="md"', 'modal-fullscreen-md-down'], | ||
['full-screen="lg"', 'modal-fullscreen-lg-down'], | ||
['full-screen="xl"', 'modal-fullscreen-xl-down'], | ||
['full-screen="xxl"', 'modal-fullscreen-xxl-down'], | ||
]; | ||
} | ||
|
||
/** | ||
* @dataProvider closeButtonOptions | ||
*/ | ||
public function testModalRendersCloseButtonCorrectly(string $closeButtonAttributes, string $footer): void | ||
{ | ||
$this->assertBladeRendersToHtml( | ||
'<div id="exampleModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true" class="modal fade"> | ||
<div class="modal-dialog"> | ||
<div class="modal-content"> | ||
<div class="modal-header"> | ||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> | ||
</div> | ||
<div class="modal-body">My modal</div>' | ||
. ($footer ? "\n" . $footer : '') . ' | ||
</div> | ||
</div> | ||
</div>', | ||
$this->bladeView('<x-bs::modal id="exampleModal" ' . $closeButtonAttributes . '>My modal</x-bs::modal>') | ||
); | ||
} | ||
|
||
public static function closeButtonOptions(): array | ||
{ | ||
return [ | ||
['', self::makeFooter('btn-secondary')], | ||
[':close-button="true"', self::makeFooter('btn-secondary')], | ||
[':close-button="false"', ''], | ||
['close-button="primary"', self::makeFooter('btn-primary')], | ||
]; | ||
} | ||
|
||
/** | ||
* @dataProvider slots | ||
*/ | ||
public function testModalRendersSlotsCorrectly(string $slots, string $header, string $footer): void | ||
{ | ||
$this->assertBladeRendersToHtml( | ||
'<div id="exampleModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true" class="modal fade"> | ||
<div class="modal-dialog"> | ||
<div class="modal-content"> | ||
' . $header . ' | ||
<div class="modal-body">My modal</div> | ||
' . $footer . ' | ||
</div> | ||
</div> | ||
</div>', | ||
$this->bladeView('<x-bs::modal id="exampleModal">My modal' . $slots . '</x-bs::modal>') | ||
); | ||
} | ||
|
||
public static function slots(): array | ||
{ | ||
return [ | ||
[ | ||
'<x-slot:title class="fs-5">Test title</x-slot>', | ||
self::makeHeader('<h1 id="exampleModalLabel" class="modal-title fs-5">Test title</h1>'), | ||
self::makeFooter('btn-secondary'), | ||
], | ||
[ | ||
'<x-slot:title container="h2" class="text-primary">Test title</x-slot>', | ||
self::makeHeader('<h2 id="exampleModalLabel" class="modal-title text-primary">Test title</h2>'), | ||
self::makeFooter('btn-secondary'), | ||
], | ||
[ | ||
'<x-slot:footer> | ||
<x-bs::button variant="primary">Submit</x-bs:button> | ||
</x-slot>', | ||
self::makeHeader(null), | ||
'<div class="modal-footer"> | ||
<button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Close</button> | ||
<button class="btn btn-primary">Submit</button></div>', | ||
], | ||
]; | ||
} | ||
|
||
private static function makeHeader(?string $title): string | ||
{ | ||
return '<div class="modal-header">' | ||
. ($title ? "\n" . $title : '') . ' | ||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> | ||
</div>'; | ||
} | ||
|
||
private static function makeFooter(?string $buttonClass): string | ||
{ | ||
if ($buttonClass === null) { | ||
return ''; | ||
} | ||
|
||
return '<div class="modal-footer"> | ||
<button class="btn ' . $buttonClass .'" type="button" data-bs-dismiss="modal">Close</button> | ||
</div>'; | ||
} | ||
} |