Skip to content

Commit

Permalink
Close button trait (#130)
Browse files Browse the repository at this point in the history
  • Loading branch information
Gerych1984 authored Nov 21, 2023
1 parent 34e66cb commit 44dbece
Show file tree
Hide file tree
Showing 11 changed files with 208 additions and 218 deletions.
15 changes: 12 additions & 3 deletions src/Accordion.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
use Stringable;
use Yiisoft\Arrays\ArrayHelper;
use Yiisoft\Html\Html;

use function array_key_exists;
use function implode;
use function is_array;
Expand Down Expand Up @@ -84,6 +83,7 @@ final class Accordion extends Widget
private bool $encodeLabels = true;
private bool $encodeTags = false;
private bool $autoCloseItems = true;
private array $itemOptions = [];
private array $headerOptions = [];
private array $toggleOptions = [];
private array $contentOptions = [];
Expand Down Expand Up @@ -202,6 +202,14 @@ public function defaultExpand(?bool $default): self
return $new;
}

public function withItemOptions(array $options): self
{
$new = clone $this;
$new->itemOptions = $options;

return $new;
}

/**
* Options for each header if not present in item
*/
Expand Down Expand Up @@ -306,12 +314,13 @@ private function renderItems(): string
throw new RuntimeException('The "label" option is required.');
}

$options = ArrayHelper::getValue($item, 'options', []);
$options = ArrayHelper::getValue($item, 'options', $this->itemOptions);
$tag = ArrayHelper::remove($options, 'tag', 'div');
$item = $this->renderItem($item);

Html::addCssClass($options, ['panel' => 'accordion-item']);

$items[] = Html::div($item, $options)
$items[] = Html::tag($tag, $item, $options)
->encode(false)
->render();

Expand Down
121 changes: 19 additions & 102 deletions src/Alert.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,9 @@

namespace Yiisoft\Yii\Bootstrap5;

use JsonException;
use Stringable;
use Yiisoft\Arrays\ArrayHelper;
use Yiisoft\Html\Html;

use function array_merge;

/**
Expand All @@ -27,17 +26,13 @@
*/
final class Alert extends Widget
{
private string $body = '';
use CloseButtonTrait;

private string|Stringable $body = '';
private ?string $header = null;
private array $headerOptions = [];
/** @psalm-var non-empty-string */
private string $headerTag = 'h4';
private array $closeButton = [
'class' => 'btn-close',
];
/** @psalm-var non-empty-string */
private string $closeButtonTag = 'button';
private bool $closeButtonInside = true;
private bool $encode = false;
private array $options = [];
private array $classNames = [];
Expand All @@ -48,29 +43,31 @@ public function getId(?string $suffix = '-alert'): ?string
return $this->options['id'] ?? parent::getId($suffix);
}

protected function toggleComponent(): string
{
return 'alert';
}

public function render(): string
{
$options = $this->prepareOptions();
$tag = ArrayHelper::remove($options, 'tag', 'div');

$content = Html::openTag($tag, $options);
$content .= $this->renderHeader();
$content .= $this->encode ? Html::encode($this->body) : $this->body;

if ($this->closeButtonInside) {
$content .= $this->renderCloseButton(false);
}

$content .= Html::closeTag($tag);

return $content;
return Html::tag($tag, '', $options)
->encode(false)
->content(
(string) $this->renderHeader(),
$this->encode ? Html::encode($this->body) : $this->body,
(string) $this->renderCloseButton(true)
)
->render();
}

/**
* The body content in the alert component. Alert widget will also be treated as the body content, and will be
* rendered before this.
*/
public function body(string $value): self
public function body(string|Stringable $value): self
{
$new = clone $this;
$new->body = $value;
Expand Down Expand Up @@ -115,54 +112,6 @@ public function headerTag(string $tag): self
return $new;
}

/**
* The options for rendering the close button tag.
*
* The close button is displayed in the header of the modal window. Clicking on the button will hide the modal
* window. If {@see closeButtonEnabled} is false, no close button will be rendered.
*
* The following special options are supported:
*
* - tag: string, the tag name of the button. Defaults to 'button'.
* - label: string, the label of the button. Defaults to '×'.
*
* The rest of the options will be rendered as the HTML attributes of the button tag.
*
* Please refer to the [Alert documentation](http://getbootstrap.com/components/#alerts) for the supported HTML
* attributes.
*/
public function closeButton(array $value): self
{
$new = clone $this;
$new->closeButton = $value;

return $new;
}

/**
* Disable close button.
*/
public function withoutCloseButton(bool $value = false): self
{
$new = clone $this;
$new->closeButtonInside = $value;

return $new;
}

/**
* Set close button tag
*
* @psalm-param non-empty-string $tag
*/
public function closeButtonTag(string $tag): self
{
$new = clone $this;
$new->closeButtonTag = $tag;

return $new;
}

/**
* The HTML attributes for the widget container tag. The following special options are recognized.
*
Expand Down Expand Up @@ -273,38 +222,6 @@ public function dark(): self
return $this->addClassNames('alert-dark');
}

/**
* Renders the close button.
*
* @throws JsonException
*
* @return string the rendering result
*/
public function renderCloseButton(bool $outside = true): ?string
{
$options = array_merge(
$this->closeButton,
[
'aria-label' => 'Close',
'data-bs-dismiss' => 'alert',
],
);
$label = ArrayHelper::remove($options, 'label', '');
$encode = ArrayHelper::remove($options, 'encode', $this->encode);

if ($this->closeButtonTag === 'button' && !isset($options['type'])) {
$options['type'] = 'button';
}

if ($outside) {
$options['data-bs-target'] = '#' . $this->getId();
}

return Html::tag($this->closeButtonTag, $label, $options)
->encode($encode)
->render();
}

/**
* Render header tag
*/
Expand Down Expand Up @@ -335,7 +252,7 @@ private function prepareOptions(): array
$options['id'] = $this->getId();
$classNames = array_merge(['alert'], $this->classNames);

if ($this->closeButtonInside) {
if ($this->showCloseButton) {
$classNames[] = 'alert-dismissible';
}

Expand Down
40 changes: 30 additions & 10 deletions src/AbstractCloseButtonWidget.php → src/CloseButtonTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,24 @@
use Yiisoft\Html\Html;
use Yiisoft\Html\Tag\Base\Tag;

abstract class AbstractCloseButtonWidget extends AbstractToggleWidget
trait CloseButtonTrait
{
protected ?array $closeButtonOptions = [];
protected string|Stringable $closeButtonLabel = '';
protected bool $encodeCloseButton = true;
private array $closeButtonOptions = [];
private string|Stringable $closeButtonLabel = '';
private bool $encodeCloseButton = true;
private bool $showCloseButton = true;


abstract protected function toggleComponent(): string;

abstract public function getId(): ?string;

/**
* The HTML attributes for the widget close button tag. The following special options are recognized.
*
* {@see Html::renderTagAttributes()} for details on how attributes are being rendered.
*/
public function withCloseButtonOptions(?array $options): static
public function withCloseButtonOptions(array $options): static
{
$new = clone $this;
$new->closeButtonOptions = $options;
Expand All @@ -33,7 +39,18 @@ public function withCloseButtonOptions(?array $options): static
*/
public function withoutCloseButton(): static
{
return $this->withCloseButtonOptions(null);
$new = clone $this;

Check warning on line 42 in src/CloseButtonTrait.php

View workflow job for this annotation

GitHub Actions / mutation / PHP 8.1-ubuntu-latest

Escaped Mutant for Mutator "CloneRemoval": --- Original +++ New @@ @@ */ public function withoutCloseButton() : static { - $new = clone $this; + $new = $this; $new->showCloseButton = false; return $new; }
$new->showCloseButton = false;

return $new;
}

public function withCloseButton(): static
{
$new = clone $this;

Check warning on line 50 in src/CloseButtonTrait.php

View workflow job for this annotation

GitHub Actions / mutation / PHP 8.1-ubuntu-latest

Escaped Mutant for Mutator "CloneRemoval": --- Original +++ New @@ @@ } public function withCloseButton() : static { - $new = clone $this; + $new = $this; $new->showCloseButton = true; return $new; }
$new->showCloseButton = true;

return $new;
}

public function withCloseButtonLabel(string|Stringable $label): static
Expand All @@ -52,21 +69,24 @@ public function withEncodeCloseButton(bool $encode): static
return $new;
}

public function renderCloseButton(): ?Tag
public function renderCloseButton(bool $inside = false): ?Tag
{
$options = $this->closeButtonOptions;

if ($options === null) {
if ($inside && $this->showCloseButton === false) {
return null;
}

$options = $this->closeButtonOptions;
$tagName = ArrayHelper::remove($options, 'tag', 'button');

Html::addCssClass($options, ['widget' => 'btn-close']);

$label = (string) $this->closeButtonLabel;

Check warning on line 83 in src/CloseButtonTrait.php

View workflow job for this annotation

GitHub Actions / mutation / PHP 8.1-ubuntu-latest

Escaped Mutant for Mutator "CastString": --- Original +++ New @@ @@ $options = $this->closeButtonOptions; $tagName = ArrayHelper::remove($options, 'tag', 'button'); Html::addCssClass($options, ['widget' => 'btn-close']); - $label = (string) $this->closeButtonLabel; + $label = $this->closeButtonLabel; $options['data-bs-dismiss'] = $this->toggleComponent(); if (!$inside) { $options['data-bs-target'] = '#' . $this->getId();
$options['data-bs-dismiss'] = $this->toggleComponent();

if (!$inside) {
$options['data-bs-target'] = '#' . $this->getId();
}

if (empty($label) && !isset($options['aria-label']) && !isset($options['aria']['label'])) {
$options['aria-label'] = 'Close';
}
Expand Down
5 changes: 2 additions & 3 deletions src/Collapse.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
use Stringable;
use Yiisoft\Arrays\ArrayHelper;
use Yiisoft\Html\Html;

use function array_key_exists;

/**
Expand Down Expand Up @@ -61,8 +60,8 @@ public function withBodyOptions(array $options): self
$new = clone $this;
$new->bodyOptions = $options;

if (!array_key_exists('tag', $this->bodyOptions)) {
$this->bodyOptions['tag'] = 'div';
if (!array_key_exists('tag', $options)) {
$new->bodyOptions['tag'] = 'div';
}

return $new;
Expand Down
7 changes: 4 additions & 3 deletions src/Modal.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
use Stringable;
use Yiisoft\Arrays\ArrayHelper;
use Yiisoft\Html\Html;

use function array_merge;

/**
Expand All @@ -28,8 +27,10 @@
* echo Modal::end();
* ```
*/
final class Modal extends AbstractCloseButtonWidget
final class Modal extends AbstractToggleWidget
{
use CloseButtonTrait;

/**
* Size classes
*/
Expand Down Expand Up @@ -382,7 +383,7 @@ public function fullscreen(?string $fullscreen): self
private function renderHeader(): string
{
$title = (string) $this->renderTitle();
$button = (string) $this->renderCloseButton();
$button = (string) $this->renderCloseButton(true);

if ($button === '' && $title === '') {
return '';
Expand Down
6 changes: 4 additions & 2 deletions src/Offcanvas.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@
use Yiisoft\Arrays\ArrayHelper;
use Yiisoft\Html\Html;

final class Offcanvas extends AbstractCloseButtonWidget
final class Offcanvas extends AbstractToggleWidget
{
use CloseButtonTrait;

public const PLACEMENT_TOP = 'offcanvas-top';
public const PLACEMENT_END = 'offcanvas-end';
public const PLACEMENT_BOTTOM = 'offcanvas-bottom';
Expand Down Expand Up @@ -200,7 +202,7 @@ private function renderHeader(): string
Html::addCssClass($options, ['widget' => 'offcanvas-header']);

$title = (string) $this->renderTitle();
$closeButton = $this->renderCloseButton();
$closeButton = $this->renderCloseButton(true);

return Html::tag($tag, $title . $closeButton, $options)
->encode(false)
Expand Down
Loading

0 comments on commit 44dbece

Please sign in to comment.