diff --git a/.github/workflows/rector-cs.yml b/.github/workflows/rector-cs.yml new file mode 100644 index 000000000..6424c2aab --- /dev/null +++ b/.github/workflows/rector-cs.yml @@ -0,0 +1,27 @@ +name: Rector + PHP CS Fixer + +on: + pull_request_target: + paths: + - 'src/**' + - 'tests/**' + - '.github/workflows/rector-cs.yml' + - 'composer.json' + - 'rector.php' + - '.php-cs-fixer.dist.php' + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + rector: + uses: yiisoft/actions/.github/workflows/rector-cs.yml@master + secrets: + token: ${{ secrets.YIISOFT_GITHUB_TOKEN }} + with: + repository: ${{ github.event.pull_request.head.repo.full_name }} + php: '8.1' diff --git a/.github/workflows/rector.yml b/.github/workflows/rector.yml deleted file mode 100644 index f8f1999b8..000000000 --- a/.github/workflows/rector.yml +++ /dev/null @@ -1,20 +0,0 @@ -on: - pull_request_target: - paths-ignore: - - 'docs/**' - - 'README.md' - - 'CHANGELOG.md' - - '.gitignore' - - '.gitattributes' - - 'infection.json.dist' - - 'psalm.xml' - -name: rector - -jobs: - rector: - uses: yiisoft/actions/.github/workflows/rector.yml@master - secrets: - token: ${{ secrets.YIISOFT_GITHUB_TOKEN }} - with: - repository: ${{ github.event.pull_request.head.repo.full_name }} diff --git a/.gitignore b/.gitignore index 63c754feb..41ddd4b6b 100644 --- a/.gitignore +++ b/.gitignore @@ -36,3 +36,7 @@ phpunit.phar /node_modules /package-lock.json .phpunit.result.cache + +# PHP CS Fixer +/.php-cs-fixer.cache +/.php-cs-fixer.php diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php new file mode 100644 index 000000000..e9cea90b9 --- /dev/null +++ b/.php-cs-fixer.dist.php @@ -0,0 +1,34 @@ +in([ + __DIR__ . '/src', + __DIR__ . '/tests', +]); + +return (new Config()) + ->setRiskyAllowed(true) + ->setParallelConfig(ParallelConfigFactory::detect()) + ->setRules([ + '@PER-CS3.0' => true, + 'no_unused_imports' => true, + 'ordered_class_elements' => true, + 'class_attributes_separation' => ['elements' => ['method' => 'one']], + 'declare_strict_types' => true, + 'native_function_invocation' => true, + 'native_constant_invocation' => true, + 'fully_qualified_strict_types' => [ + 'import_symbols' => true + ], + 'global_namespace_import' => [ + 'import_classes' => true, + 'import_constants' => true, + 'import_functions' => true, + ], + ]) + ->setFinder($finder); diff --git a/.styleci.yml b/.styleci.yml deleted file mode 100644 index 2bebb346f..000000000 --- a/.styleci.yml +++ /dev/null @@ -1,87 +0,0 @@ -preset: psr12 -risky: true - -version: 8.1 - -finder: - exclude: - - docs - - vendor - not-name: - - "rector.php" - -enabled: - - alpha_ordered_traits - - array_indentation - - array_push - - combine_consecutive_issets - - combine_consecutive_unsets - - combine_nested_dirname - - declare_strict_types - - dir_constant - - fully_qualified_strict_types - - function_to_constant - - hash_to_slash_comment - - is_null - - logical_operators - - magic_constant_casing - - magic_method_casing - - method_separation - - modernize_types_casting - - native_function_casing - - native_function_type_declaration_casing - - no_alias_functions - - no_empty_comment - - no_empty_phpdoc - - no_empty_statement - - no_extra_block_blank_lines - - no_short_bool_cast - - no_superfluous_elseif - - no_unneeded_control_parentheses - - no_unneeded_curly_braces - - no_unneeded_final_method - - no_unset_cast - - no_unused_imports - - no_unused_lambda_imports - - no_useless_else - - no_useless_return - - normalize_index_brace - - php_unit_dedicate_assert - - php_unit_dedicate_assert_internal_type - - php_unit_expectation - - php_unit_mock - - php_unit_mock_short_will_return - - php_unit_namespaced - - php_unit_no_expectation_annotation - - phpdoc_no_empty_return - - phpdoc_no_useless_inheritdoc - - phpdoc_order - - phpdoc_property - - phpdoc_scalar - - phpdoc_singular_inheritdoc - - phpdoc_trim - - phpdoc_trim_consecutive_blank_line_separation - - phpdoc_type_to_var - - phpdoc_types - - phpdoc_types_order - - print_to_echo - - regular_callable_call - - return_assignment - - self_accessor - - self_static_accessor - - set_type_to_cast - - short_array_syntax - - short_list_syntax - - simplified_if_return - - single_quote - - standardize_not_equals - - ternary_to_null_coalescing - - trailing_comma_in_multiline_array - - unalign_double_arrow - - unalign_equals - - empty_loop_body_braces - - integer_literal_case - - union_type_without_spaces - -disabled: - - function_declaration diff --git a/CHANGELOG.md b/CHANGELOG.md index df8c0a4c1..1228e0d4f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ - Enh #287: Allow `Dropdown::togglerVariant()` to be `null`, avoiding it setting a variant class (@Mister-42) - Bug #288: Add support for custom togglerClasses in `Dropdown` widget, and `addDropdownClass()` method (@terabytesoftw) - Enh #291: Add `navId()` method to `NavBar` widget (@terabytesoftw) +- Enh #294: Explicitly import classes and functions in "use" section (@mspirkov) ## 1.0.0 April 13, 2025 diff --git a/composer.json b/composer.json index c05fb8262..aff078d1f 100644 --- a/composer.json +++ b/composer.json @@ -21,6 +21,7 @@ "yiisoft/widget": "^2.0" }, "require-dev": { + "friendsofphp/php-cs-fixer": "^3.92.5", "maglnet/composer-require-checker": "^4.1", "phpunit/phpunit": "^10.5", "rector/rector": "^2.0", diff --git a/src/Accordion.php b/src/Accordion.php index c1cb1f759..5578adbd7 100644 --- a/src/Accordion.php +++ b/src/Accordion.php @@ -67,7 +67,7 @@ final class Accordion extends Widget private array $togglerAttributes = []; - private string|null $togglerTag = null; + private ?string $togglerTag = null; /** * Adds a sets of attributes. diff --git a/src/AccordionItem.php b/src/AccordionItem.php index 1986f8075..3249bc638 100644 --- a/src/AccordionItem.php +++ b/src/AccordionItem.php @@ -37,8 +37,7 @@ private function __construct( private bool $encodeHeader, private string $header, private bool|string $id, - ) { - } + ) {} /** * Creates a new {@see AccordionItem} instance. @@ -59,7 +58,7 @@ public static function to( bool|string $id = true, bool $encodeHeader = true, bool $encodeBody = true, - bool $active = false + bool $active = false, ): self { return new self($active, $body, $encodeBody, $encodeHeader, $header, $id); } diff --git a/src/Alert.php b/src/Alert.php index eba89c8c0..a926895a1 100644 --- a/src/Alert.php +++ b/src/Alert.php @@ -43,7 +43,7 @@ final class Alert extends Widget private array $closeButtonAttributes = []; - private string|null $closeButtonTag = null; + private ?string $closeButtonTag = null; private string $closeButtonLabel = ''; @@ -51,7 +51,7 @@ final class Alert extends Widget private bool $fade = false; - private string|null $header = null; + private ?string $header = null; private array $headerAttributes = []; @@ -417,7 +417,7 @@ public function fade(bool $enabled): self * $alert->header('Header content'); * ``` */ - public function header(string|null $content, bool $encode = true): self + public function header(?string $content, bool $encode = true): self { if ($encode) { $content = Html::encode($content); @@ -562,7 +562,7 @@ public function render(): string '{header}' => $this->renderHeader(), '{body}' => $this->body, '{toggler}' => $toggler, - ] + ], ); $content = preg_replace("/\n{2}/", "\n", $content) ?? ''; @@ -577,7 +577,7 @@ public function render(): string * * @psalm-return non-empty-string|null The generated ID. */ - private function getId(): string|null + private function getId(): ?string { return match ($this->id) { true => $this->attributes['id'] ?? Html::generateId(self::NAME . '-'), diff --git a/src/BreadcrumbLink.php b/src/BreadcrumbLink.php index 17f3bb778..ea3902457 100644 --- a/src/BreadcrumbLink.php +++ b/src/BreadcrumbLink.php @@ -31,12 +31,11 @@ final class BreadcrumbLink */ private function __construct( private string $label, - private string|null $url, + private ?string $url, private bool $active, private bool $encodeLabel, private array $attributes, - ) { - } + ) {} /** * Creates a new {@see BreadcrumbLink} instance. @@ -51,10 +50,10 @@ private function __construct( */ public static function to( string $label, - string|null $url = null, + ?string $url = null, bool $active = false, array $attributes = [], - bool $encodeLabel = true + bool $encodeLabel = true, ): self { return new self($label, $url, $active, $encodeLabel, $attributes); } @@ -128,7 +127,7 @@ public function label(string $label): self * * @return self A new instance with the specified URL. */ - public function url(string|null $url): self + public function url(?string $url): self { $new = clone $this; $new->url = $url; @@ -156,7 +155,7 @@ public function getLabel(): string /** * @return string|null The URL for the link. */ - public function getUrl(): string|null + public function getUrl(): ?string { return $this->url; } diff --git a/src/Breadcrumbs.php b/src/Breadcrumbs.php index 8813f48f3..db20b6e89 100644 --- a/src/Breadcrumbs.php +++ b/src/Breadcrumbs.php @@ -422,7 +422,7 @@ public function render(): string * * @psalm-return non-empty-string|null The generated ID. */ - private function getId(): string|null + private function getId(): ?string { return match ($this->listId) { true => $this->listAttributes['id'] ?? Html::generateId(self::LIST_NAME . '-'), diff --git a/src/Button.php b/src/Button.php index cac8ddf2c..2d3cfb8f2 100644 --- a/src/Button.php +++ b/src/Button.php @@ -38,7 +38,7 @@ final class Button extends Widget private array $attributes = []; - private ButtonVariant|null $buttonVariant = ButtonVariant::SECONDARY; + private ?ButtonVariant $buttonVariant = ButtonVariant::SECONDARY; private array $cssClasses = []; @@ -73,10 +73,10 @@ final class Button extends Widget */ public static function link( string|Stringable $label = '', - string|null $url = null, + ?string $url = null, array $constructorArguments = [], array $config = [], - string|null $theme = null + ?string $theme = null, ): self { return self::widget($constructorArguments, $config, $theme)->label($label)->type(ButtonType::LINK)->url($url); } @@ -105,7 +105,7 @@ public static function resetInput( string|Stringable $value = 'Reset', array $constructorArguments = [], array $config = [], - string|null $theme = null + ?string $theme = null, ): self { return self::widget($constructorArguments, $config, $theme)->label($value)->type(ButtonType::RESET_INPUT); } @@ -134,7 +134,7 @@ public static function submitInput( string|Stringable $value = 'Submit', array $constructorArguments = [], array $config = [], - string|null $theme = null + ?string $theme = null, ): self { return self::widget($constructorArguments, $config, $theme)->label($value)->type(ButtonType::SUBMIT_INPUT); } @@ -163,7 +163,7 @@ public static function reset( string|Stringable $value = 'Reset', array $constructorArguments = [], array $config = [], - string|null $theme = null + ?string $theme = null, ): self { return self::widget($constructorArguments, $config, $theme)->label($value)->type(ButtonType::RESET); } @@ -192,7 +192,7 @@ public static function submit( string|Stringable $value = 'Submit', array $constructorArguments = [], array $config = [], - string|null $theme = null + ?string $theme = null, ): self { return self::widget($constructorArguments, $config, $theme)->label($value)->type(ButtonType::SUBMIT); } @@ -467,7 +467,7 @@ public function label(string|Stringable $label, bool $encode = true): self * $button->size(ButtonSize::LARGE); * ``` */ - public function size(ButtonSize|null $size): self + public function size(?ButtonSize $size): self { return $this->addClass($size?->value); } @@ -485,7 +485,7 @@ public function size(ButtonSize|null $size): self * $button->toggle(TogglerType::BUTTON); * ``` */ - public function toggle(TogglerType|null $type = TogglerType::BUTTON): self + public function toggle(?TogglerType $type = TogglerType::BUTTON): self { return $this->attribute('data-bs-toggle', $type?->value); } @@ -528,7 +528,7 @@ public function type(ButtonType $type): self * $button->url('/path/to/page'); * ``` */ - public function url(string|null $url): self + public function url(?string $url): self { return $this->attribute('href', $url); } @@ -545,7 +545,7 @@ public function url(string|null $url): self * $button->variant(ButtonVariant::PRIMARY); * ``` */ - public function variant(ButtonVariant|null $variant): self + public function variant(?ButtonVariant $variant): self { $new = clone $this; $new->buttonVariant = $variant; @@ -589,7 +589,7 @@ public function render(): string * * @psalm-return non-empty-string|null The generated ID. */ - private function getId(): string|null + private function getId(): ?string { return match ($this->id) { true => $this->attributes['id'] ?? Html::generateId(self::NAME . '-'), diff --git a/src/ButtonGroup.php b/src/ButtonGroup.php index 91762b8ff..94e353a73 100644 --- a/src/ButtonGroup.php +++ b/src/ButtonGroup.php @@ -260,7 +260,7 @@ public function id(bool|string $id): self * $buttonGroup->size(ButtonSize::LARGE); * ``` */ - public function size(ButtonSize|null $size): self + public function size(?ButtonSize $size): self { return $this->addClass($size?->value); } @@ -320,7 +320,7 @@ public function render(): string * * @psalm-return non-empty-string|null The generated ID. */ - private function getId(): string|null + private function getId(): ?string { return match ($this->id) { true => $this->attributes['id'] ?? Html::generateId(self::NAME . '-'), diff --git a/src/ButtonToolbar.php b/src/ButtonToolbar.php index ed2db4de4..6fe472e23 100644 --- a/src/ButtonToolbar.php +++ b/src/ButtonToolbar.php @@ -295,7 +295,7 @@ public function render(): string * * @psalm-return non-empty-string|null The generated ID. */ - private function getId(): string|null + private function getId(): ?string { return match ($this->id) { true => $this->attributes['id'] ?? Html::generateId(self::NAME . '-'), diff --git a/src/Carousel.php b/src/Carousel.php index ed131bfb4..0608616e8 100644 --- a/src/Carousel.php +++ b/src/Carousel.php @@ -639,7 +639,7 @@ private function renderItem(CarouselItem $carouselItem, bool $active): string if ($caption !== null && $caption !== '') { if ($this->captionTagName === '' || $this->captionPlaceholderTagName === '') { throw new InvalidArgumentException( - 'The "captionTagName" and "captionPlaceholderTagName" properties cannot be empty.' + 'The "captionTagName" and "captionPlaceholderTagName" properties cannot be empty.', ); } @@ -654,14 +654,14 @@ private function renderItem(CarouselItem $carouselItem, bool $active): string Html::tag($this->captionPlaceholderTagName) ->addAttributes($carouselItem->getCaptionPlaceholderAttributes()) ->addContent($carouselItem->getcaptionPlaceholder() ?? ''), - "\n" + "\n", ) . "\n"; } return Div::tag() ->addClass( self::CLASS_CAROUSEL_ITEM, - $carouselItem->isActive() || $active ? 'active' : null + $carouselItem->isActive() || $active ? 'active' : null, ) ->addAttributes(['data-bs-interval' => $carouselItem->getAutoPlayingInterval()]) ->addContent( @@ -687,7 +687,7 @@ private function renderItems(string $id): string $indicators = []; $renderIndicators = ''; - $activeItems = array_filter($this->items, static fn (CarouselItem $item): bool => $item->isActive()); + $activeItems = array_filter($this->items, static fn(CarouselItem $item): bool => $item->isActive()); if (count($activeItems) > 1) { throw new InvalidArgumentException('Only one carousel item can be active at a time.'); @@ -711,8 +711,8 @@ private function renderItems(string $id): string ->render() . "\n"; } - return $renderIndicators . - Div::tag() + return $renderIndicators + . Div::tag() ->addClass(self::CLASS_CAROUSEL_INNER) ->addContent("\n" . implode("\n", $items) . "\n") ->encode(false) diff --git a/src/CarouselItem.php b/src/CarouselItem.php index 0c634729e..93c6ba9d0 100644 --- a/src/CarouselItem.php +++ b/src/CarouselItem.php @@ -45,16 +45,15 @@ final class CarouselItem private function __construct( private bool $active, private array $attributes, - private int|null $autoPlayingInterval, - private string|null $caption, + private ?int $autoPlayingInterval, + private ?string $caption, private array $captionAttributes, - private string|null $captionPlaceholder, + private ?string $captionPlaceholder, private array $captionPlaceholderAttributes, private string|Stringable $content, private bool $encodeCaption, private bool $encodeCaptionPlaceholder, - ) { - } + ) {} /** * Creates a new {@see CarouselItem} instance. @@ -74,9 +73,9 @@ private function __construct( */ public static function to( string|Stringable $content = '', - string|null $caption = null, - string|null $captionPlaceholder = null, - int|null $autoPlayingInterval = null, + ?string $caption = null, + ?string $captionPlaceholder = null, + ?int $autoPlayingInterval = null, bool $active = false, bool $encodeCaption = true, bool $encodeCaptionPlaceholder = true, @@ -265,7 +264,7 @@ public function getAttributes(): array /** * @return int|null Returns the autoplaying interval for the carousel item. */ - public function getAutoPlayingInterval(): int|null + public function getAutoPlayingInterval(): ?int { return $this->autoPlayingInterval; } @@ -273,7 +272,7 @@ public function getAutoPlayingInterval(): int|null /** * @return string|null Returns the caption content for the carousel item. */ - public function getCaption(): string|null + public function getCaption(): ?string { return $this->encodeCaption ? Html::encode($this->caption) : $this->caption; } @@ -289,7 +288,7 @@ public function getCaptionAttributes(): array /** * @return string|null Returns the caption placeholder content for the carousel item. */ - public function getCaptionPlaceholder(): string|null + public function getCaptionPlaceholder(): ?string { return $this->encodeCaptionPlaceholder ? Html::encode($this->captionPlaceholder) : $this->captionPlaceholder; } diff --git a/src/Collapse.php b/src/Collapse.php index 164975a9c..895d7a4f7 100644 --- a/src/Collapse.php +++ b/src/Collapse.php @@ -368,9 +368,9 @@ public function render(): string ->addContent( "\n", $item->getContent(), - "\n" + "\n", ), - "\n" + "\n", ) ->id($item->getId()); diff --git a/src/Dropdown.php b/src/Dropdown.php index 7a6403df4..43acebc81 100644 --- a/src/Dropdown.php +++ b/src/Dropdown.php @@ -95,13 +95,13 @@ final class Dropdown extends Widget private string $togglerUrl = '#'; - private string|null $togglerSize = null; + private ?string $togglerSize = null; private bool $togglerSplit = false; private string $togglerSplitContent = 'Action'; - private ButtonVariant|null $togglerVariant = ButtonVariant::SECONDARY; + private ?ButtonVariant $togglerVariant = ButtonVariant::SECONDARY; /** * Adds a sets of attributes. @@ -264,7 +264,7 @@ public function addTogglerCssStyle(array|string $style, bool $overwrite = true): * $dropdown->alignment(DropdownAlignment::END()); * ``` */ - public function alignment(DropdownAlignment|null ...$alignment): self + public function alignment(?DropdownAlignment ...$alignment): self { $new = clone $this; $new->alignmentClasses = $alignment; @@ -628,7 +628,7 @@ public function togglerId(bool|string $id): self * $dropdown->togglerSize(ButtonSize::SMALL()); * ``` */ - public function togglerSize(ButtonSize|null $size): self + public function togglerSize(?ButtonSize $size): self { $new = clone $this; $new->togglerSize = $size?->value; @@ -704,7 +704,7 @@ public function togglerUrl(string $url): self * * @return self A new instance with the specified variant for the toggler. */ - public function togglerVariant(ButtonVariant|null $variant): self + public function togglerVariant(?ButtonVariant $variant): self { $new = clone $this; $new->togglerVariant = $variant; @@ -768,7 +768,7 @@ public function render(): string * * @psalm-return non-empty-string|null The generated ID. */ - private function getTogglerId(): string|null + private function getTogglerId(): ?string { return match ($this->togglerId) { true => $this->attributes['id'] ?? Html::generateId(self::NAME . '-'), @@ -813,7 +813,7 @@ private function renderItemButton(DropdownItem $item): Li ->addAttributes($item->getItemAttributes()) ->addContent($item->getContent()) ->addClass(self::DROPDOWN_ITEM_CLASS), - "\n" + "\n", ); } @@ -831,7 +831,7 @@ private function renderItemDivider(DropdownItem $item): Li ->addContent( "\n", Hr::tag()->addAttributes($item->getItemAttributes())->addClass(self::DROPDOWN_ITEM_DIVIDER_CLASS), - "\n" + "\n", ); } @@ -852,7 +852,7 @@ private function renderItemHeader(DropdownItem $item): Li ->addAttributes($item->getItemAttributes()) ->addClass(self::DROPDOWN_ITEM_HEADER_CLASS) ->content($item->getContent()), - "\n" + "\n", ); } @@ -920,7 +920,7 @@ private function renderItemText(DropdownItem $item): Li ->addClass(self::DROPDOWN_ITEM_TEXT_CLASS) ->content($item->getContent()) ->encode(false), - "\n" + "\n", ); } @@ -933,7 +933,7 @@ private function renderItemText(DropdownItem $item): Li * * @psalm-param non-empty-string|null $togglerId */ - private function renderItems(string|null $togglerId): string + private function renderItems(?string $togglerId): string { $items = []; @@ -958,19 +958,19 @@ private function renderItems(string|null $togglerId): string * * @psalm-param non-empty-string|null $togglerId */ - private function renderToggler(string|null $togglerId): string + private function renderToggler(?string $togglerId): string { if ($this->toggler !== '') { return (string) $this->toggler; } $togglerContent = match ($this->togglerSplit) { - true => "\n" . - Span::tag() + true => "\n" + . Span::tag() ->addContent($this->togglerContent) ->addClass(self::DROPDOWN_TOGGLER_SPAN_CLASS) - ->render() . - "\n", + ->render() + . "\n", default => $this->togglerContent, }; diff --git a/src/DropdownItem.php b/src/DropdownItem.php index 5b29e63a2..74403fd32 100644 --- a/src/DropdownItem.php +++ b/src/DropdownItem.php @@ -52,8 +52,7 @@ private function __construct( private array $attributes, private array $itemAttributes, private string $headerTag, - ) { - } + ) {} /** * Creates a button-type dropdown item. diff --git a/src/Modal.php b/src/Modal.php index 28681dce6..3c6ce5b4c 100644 --- a/src/Modal.php +++ b/src/Modal.php @@ -13,6 +13,9 @@ use Yiisoft\Html\Tag\Div; use Yiisoft\Widget\Widget; +use function array_key_exists; +use function is_string; + /** * Modal renders a modal window that can be toggled by clicking on a trigger element. * @@ -620,7 +623,7 @@ public function render(): string * * @psalm-return non-empty-string|null The generated ID. */ - private function getId(): string|null + private function getId(): ?string { return match ($this->id) { true => $this->attributes['id'] ?? Html::generateId(self::NAME . '-'), diff --git a/src/Nav.php b/src/Nav.php index 50c6a0145..b2155ce50 100644 --- a/src/Nav.php +++ b/src/Nav.php @@ -422,6 +422,55 @@ public function tag(string|Stringable $tag): self return $new; } + /** + * Run the nav widget. + * + * @return string The HTML representation of the element. + */ + public function render(): string + { + if ($this->items === []) { + return ''; + } + + $attributes = $this->attributes; + $classes = $attributes['class'] ?? null; + $tabContent = ''; + + /** @psalm-var non-empty-string|null $id */ + $id = match ($this->id) { + true => $attributes['id'] ?? Html::generateId(self::NAME . '-'), + '', false => null, + default => $this->id, + }; + + unset($attributes['class'], $attributes['id']); + + if (in_array(NavStyle::NAVBAR, $this->styleClasses, true)) { + Html::addCssClass($attributes, [...$this->styleClasses, ...$this->cssClasses, $classes]); + } else { + Html::addCssClass($attributes, [self::NAME, ...$this->styleClasses, ...$this->cssClasses, $classes]); + } + + if ($this->isTabsOrPills()) { + $tabContent = $this->renderTabContent(); + } + + if ($tabContent !== '') { + $attributes['role'] = 'tablist'; + } + + $html = $this->tag === '' + ? Ul::tag()->addAttributes($attributes)->id($id)->items(...$this->renderItems())->render() + : Html::tag($this->tag) + ->addAttributes($attributes) + ->addContent("\n", implode("\n", $this->createLinks()), "\n") + ->encode(false) + ->render(); + + return $html . $tabContent; + } + /** * Create a link or button for the navigation component. * @@ -520,9 +569,9 @@ private function isDropdownActive(Dropdown $dropdown): Dropdown foreach ($items as $key => $value) { if ( - $this->activateItems && - $value->getType() === DropdownItemType::LINK && - $value->getUrl() === $this->currentPath + $this->activateItems + && $value->getType() === DropdownItemType::LINK + && $value->getUrl() === $this->currentPath ) { $items[$key] = DropdownItem::link($value->getContent(), $value->getUrl(), active: true); } @@ -538,57 +587,8 @@ private function isDropdownActive(Dropdown $dropdown): Dropdown */ private function isTabsOrPills(): bool { - return in_array(NavStyle::TABS, $this->styleClasses, true) || - in_array(NavStyle::PILLS, $this->styleClasses, true); - } - - /** - * Run the nav widget. - * - * @return string The HTML representation of the element. - */ - public function render(): string - { - if ($this->items === []) { - return ''; - } - - $attributes = $this->attributes; - $classes = $attributes['class'] ?? null; - $tabContent = ''; - - /** @psalm-var non-empty-string|null $id */ - $id = match ($this->id) { - true => $attributes['id'] ?? Html::generateId(self::NAME . '-'), - '', false => null, - default => $this->id, - }; - - unset($attributes['class'], $attributes['id']); - - if (in_array(NavStyle::NAVBAR, $this->styleClasses, true)) { - Html::addCssClass($attributes, [...$this->styleClasses, ...$this->cssClasses, $classes]); - } else { - Html::addCssClass($attributes, [self::NAME, ...$this->styleClasses, ...$this->cssClasses, $classes]); - } - - if ($this->isTabsOrPills()) { - $tabContent = $this->renderTabContent(); - } - - if ($tabContent !== '') { - $attributes['role'] = 'tablist'; - } - - $html = $this->tag === '' - ? Ul::tag()->addAttributes($attributes)->id($id)->items(...$this->renderItems())->render() - : Html::tag($this->tag) - ->addAttributes($attributes) - ->addContent("\n", implode("\n", $this->createLinks()), "\n") - ->encode(false) - ->render(); - - return $html . $tabContent; + return in_array(NavStyle::TABS, $this->styleClasses, true) + || in_array(NavStyle::PILLS, $this->styleClasses, true); } /** @@ -631,7 +631,7 @@ private function renderItemsDropdown(Dropdown $items): Li ->togglerAsLink() ->togglerClass('nav-link', 'dropdown-toggle') ->render(), - "\n" + "\n", ) ->encode(false); } @@ -679,8 +679,8 @@ private function renderTabContent(): string Html::addCssClass($paneAttributes, ['widget' => 'tab-content']); - return "\n" . - Div::tag() + return "\n" + . Div::tag() ->addAttributes($paneAttributes) ->content("\n" . implode("\n", $panes) . "\n") ->encode(false) @@ -721,7 +721,7 @@ private function renderTabPane(NavLink $item): string 'role' => 'tabpanel', 'aria-labelledby' => $item->getId(), 'tabindex' => 0, - ] + ], ) ->content($item->getContent()) ->encode($item->shouldEncodeContent()) diff --git a/src/NavBar.php b/src/NavBar.php index 0598ff656..06cc58a82 100644 --- a/src/NavBar.php +++ b/src/NavBar.php @@ -11,6 +11,7 @@ use Yiisoft\Html\Tag\Button; use Yiisoft\Html\Tag\Span; use Yiisoft\Widget\Widget; +use Yiisoft\Widget\Menu; use function array_key_exists; @@ -18,7 +19,7 @@ * `NavBar` renders a navbar HTML component. * * Any content enclosed between the {@see begin()} and {@see end()} calls of NavBar is treated as the content of the - * navbar. You may use widgets such as {@see Nav} or {@see \Yiisoft\Widget\Menu} to build up such content. For example, + * navbar. You may use widgets such as {@see Nav} or {@see Menu} to build up such content. For example, * * ```php * url; } @@ -343,7 +342,7 @@ public function paneAttributes(array $attributes): self * * @return self New instance with the specified URL. */ - public function url(string|null $url): self + public function url(?string $url): self { $new = clone $this; $new->url = $url; diff --git a/src/Progress.php b/src/Progress.php index dcc1d9cef..ac75bae91 100644 --- a/src/Progress.php +++ b/src/Progress.php @@ -371,7 +371,7 @@ public function percent(int|float $percent): self { if ($percent < 0) { throw new LogicException( - sprintf('"$percent" must be positive. %d given', $percent) + sprintf('"$percent" must be positive. %d given', $percent), ); } @@ -480,7 +480,7 @@ public function render(): string * * @psalm-return non-empty-string|null The generated ID. */ - private function getId(): string|null + private function getId(): ?string { return match ($this->id) { true => $this->attributes['id'] ?? Html::generateId(self::NAME . '-'), diff --git a/src/ProgressStack.php b/src/ProgressStack.php index b91ae2299..2f71c490e 100644 --- a/src/ProgressStack.php +++ b/src/ProgressStack.php @@ -269,7 +269,7 @@ public function render(): string * * @psalm-return non-empty-string|null The generated ID. */ - private function getId(): string|null + private function getId(): ?string { return match ($this->id) { true => $this->attributes['id'] ?? Html::generateId(self::NAME . '-'), diff --git a/src/Toast.php b/src/Toast.php index 04b904212..5dc3c5173 100644 --- a/src/Toast.php +++ b/src/Toast.php @@ -626,7 +626,7 @@ public function render(): string * * @psalm-return non-empty-string|null The generated ID. */ - private function getId(): string|null + private function getId(): ?string { return match ($this->id) { true => $this->attributes['id'] ?? Html::generateId(self::NAME . '-'), diff --git a/src/Toggler.php b/src/Toggler.php index fd581c452..f57c03bf3 100644 --- a/src/Toggler.php +++ b/src/Toggler.php @@ -52,8 +52,7 @@ private function __construct( private bool $encode, private bool $togglerMultiple, private string $ariaControls, - ) { - } + ) {} public static function for( string $content = '', @@ -106,7 +105,7 @@ public function ariaControls(string $ariaControls): self public function content(string|Stringable $content): self { $new = clone $this; - $new->content = (string)$content; + $new->content = (string) $content; return $new; } diff --git a/tests/AccordionTest.php b/tests/AccordionTest.php index a585ba236..a23be51bd 100644 --- a/tests/AccordionTest.php +++ b/tests/AccordionTest.php @@ -476,35 +476,35 @@ public function testAlwaysOpen(): void ->items( AccordionItem::to( 'Accordion Item #1', - "This is the first item's accordion body." . - ' It is shown by default, until the collapse plugin adds the appropriate classes that we use to style each element. ' . - ' These classes control the overall appearance, as well as the showing and hiding via CSS transitions. ' . - ' You can modify any of this with custom CSS or overriding our default variables. ' . - " It's also worth noting that just about any HTML can go within the .accordion-body, though the transition does limit overflow.", + "This is the first item's accordion body." + . ' It is shown by default, until the collapse plugin adds the appropriate classes that we use to style each element. ' + . ' These classes control the overall appearance, as well as the showing and hiding via CSS transitions. ' + . ' You can modify any of this with custom CSS or overriding our default variables. ' + . " It's also worth noting that just about any HTML can go within the .accordion-body, though the transition does limit overflow.", 'accordion-1', encodeBody: false, - active: true + active: true, ), AccordionItem::to( 'Accordion Item #2', - "This is the second item's accordion body." . - ' It is hidden by default, until the collapse plugin adds the appropriate classes that we use to style each element. ' . - ' These classes control the overall appearance, as well as the showing and hiding via CSS transitions. ' . - ' You can modify any of this with custom CSS or overriding our default variables. ' . - " It's also worth noting that just about any HTML can go within the .accordion-body, though the transition does limit overflow.", + "This is the second item's accordion body." + . ' It is hidden by default, until the collapse plugin adds the appropriate classes that we use to style each element. ' + . ' These classes control the overall appearance, as well as the showing and hiding via CSS transitions. ' + . ' You can modify any of this with custom CSS or overriding our default variables. ' + . " It's also worth noting that just about any HTML can go within the .accordion-body, though the transition does limit overflow.", 'accordion-2', - encodeBody: false + encodeBody: false, ), AccordionItem::to( 'Accordion Item #3', - "This is the third item's accordion body." . - ' It is hidden by default, until the collapse plugin adds the appropriate classes that we use to style each element. ' . - ' These classes control the overall appearance, as well as the showing and hiding via CSS transitions. ' . - ' You can modify any of this with custom CSS or overriding our default variables. ' . - " It's also worth noting that just about any HTML can go within the .accordion-body, though the transition does limit overflow.", + "This is the third item's accordion body." + . ' It is hidden by default, until the collapse plugin adds the appropriate classes that we use to style each element. ' + . ' These classes control the overall appearance, as well as the showing and hiding via CSS transitions. ' + . ' You can modify any of this with custom CSS or overriding our default variables. ' + . " It's also worth noting that just about any HTML can go within the .accordion-body, though the transition does limit overflow.", 'accordion-3', - encodeBody: false - ) + encodeBody: false, + ), ) ->render(), ); @@ -650,33 +650,33 @@ public function testFlush(): void ->items( AccordionItem::to( 'Accordion Item #1', - "This is the first item's accordion body." . - ' It is shown by default, until the collapse plugin adds the appropriate classes that we use to style each element. ' . - ' These classes control the overall appearance, as well as the showing and hiding via CSS transitions. ' . - ' You can modify any of this with custom CSS or overriding our default variables. ' . - " It's also worth noting that just about any HTML can go within the .accordion-body, though the transition does limit overflow.", + "This is the first item's accordion body." + . ' It is shown by default, until the collapse plugin adds the appropriate classes that we use to style each element. ' + . ' These classes control the overall appearance, as well as the showing and hiding via CSS transitions. ' + . ' You can modify any of this with custom CSS or overriding our default variables. ' + . " It's also worth noting that just about any HTML can go within the .accordion-body, though the transition does limit overflow.", 'accordion-1', - encodeBody: false + encodeBody: false, ), AccordionItem::to( 'Accordion Item #2', - "This is the second item's accordion body." . - ' It is hidden by default, until the collapse plugin adds the appropriate classes that we use to style each element. ' . - ' These classes control the overall appearance, as well as the showing and hiding via CSS transitions. ' . - ' You can modify any of this with custom CSS or overriding our default variables. ' . - " It's also worth noting that just about any HTML can go within the .accordion-body, though the transition does limit overflow.", + "This is the second item's accordion body." + . ' It is hidden by default, until the collapse plugin adds the appropriate classes that we use to style each element. ' + . ' These classes control the overall appearance, as well as the showing and hiding via CSS transitions. ' + . ' You can modify any of this with custom CSS or overriding our default variables. ' + . " It's also worth noting that just about any HTML can go within the .accordion-body, though the transition does limit overflow.", 'accordion-2', - encodeBody: false + encodeBody: false, ), AccordionItem::to( 'Accordion Item #3', - "This is the third item's accordion body." . - ' It is hidden by default, until the collapse plugin adds the appropriate classes that we use to style each element. ' . - ' These classes control the overall appearance, as well as the showing and hiding via CSS transitions. ' . - ' You can modify any of this with custom CSS or overriding our default variables. ' . - " It's also worth noting that just about any HTML can go within the .accordion-body, though the transition does limit overflow.", + "This is the third item's accordion body." + . ' It is hidden by default, until the collapse plugin adds the appropriate classes that we use to style each element. ' + . ' These classes control the overall appearance, as well as the showing and hiding via CSS transitions. ' + . ' You can modify any of this with custom CSS or overriding our default variables. ' + . " It's also worth noting that just about any HTML can go within the .accordion-body, though the transition does limit overflow.", 'accordion-3', - encodeBody: false + encodeBody: false, ), ) ->render(), @@ -735,34 +735,34 @@ public function testFlushWithFalse(): void ->items( AccordionItem::to( 'Accordion Item #1', - "This is the first item's accordion body." . - ' It is shown by default, until the collapse plugin adds the appropriate classes that we use to style each element. ' . - ' These classes control the overall appearance, as well as the showing and hiding via CSS transitions. ' . - ' You can modify any of this with custom CSS or overriding our default variables. ' . - " It's also worth noting that just about any HTML can go within the .accordion-body, though the transition does limit overflow.", + "This is the first item's accordion body." + . ' It is shown by default, until the collapse plugin adds the appropriate classes that we use to style each element. ' + . ' These classes control the overall appearance, as well as the showing and hiding via CSS transitions. ' + . ' You can modify any of this with custom CSS or overriding our default variables. ' + . " It's also worth noting that just about any HTML can go within the .accordion-body, though the transition does limit overflow.", 'accordion-1', encodeBody: false, - active: true + active: true, ), AccordionItem::to( 'Accordion Item #2', - "This is the second item's accordion body." . - ' It is hidden by default, until the collapse plugin adds the appropriate classes that we use to style each element. ' . - ' These classes control the overall appearance, as well as the showing and hiding via CSS transitions. ' . - ' You can modify any of this with custom CSS or overriding our default variables. ' . - " It's also worth noting that just about any HTML can go within the .accordion-body, though the transition does limit overflow.", + "This is the second item's accordion body." + . ' It is hidden by default, until the collapse plugin adds the appropriate classes that we use to style each element. ' + . ' These classes control the overall appearance, as well as the showing and hiding via CSS transitions. ' + . ' You can modify any of this with custom CSS or overriding our default variables. ' + . " It's also worth noting that just about any HTML can go within the .accordion-body, though the transition does limit overflow.", 'accordion-2', - encodeBody: false + encodeBody: false, ), AccordionItem::to( 'Accordion Item #3', - "This is the third item's accordion body." . - ' It is hidden by default, until the collapse plugin adds the appropriate classes that we use to style each element. ' . - ' These classes control the overall appearance, as well as the showing and hiding via CSS transitions. ' . - ' You can modify any of this with custom CSS or overriding our default variables. ' . - " It's also worth noting that just about any HTML can go within the .accordion-body, though the transition does limit overflow.", + "This is the third item's accordion body." + . ' It is hidden by default, until the collapse plugin adds the appropriate classes that we use to style each element. ' + . ' These classes control the overall appearance, as well as the showing and hiding via CSS transitions. ' + . ' You can modify any of this with custom CSS or overriding our default variables. ' + . " It's also worth noting that just about any HTML can go within the .accordion-body, though the transition does limit overflow.", 'accordion-3', - encodeBody: false + encodeBody: false, ), ) ->render(), @@ -945,13 +945,13 @@ public function testItemsWithActive(): void AccordionItem::to( 'Accordion Item #1', "This is the first item's accordion body.", - 'accordion-1' + 'accordion-1', ), AccordionItem::to( 'Accordion Item #2', "This is the second item's accordion body.", 'accordion-2', - active: true + active: true, ), ) ->render(), @@ -995,13 +995,13 @@ public function testItemsWithMultipleActive(): void 'Accordion Item #1', "This is the first item's accordion body.", 'accordion-1', - active: true + active: true, ), AccordionItem::to( 'Accordion Item #2', "This is the second item's accordion body.", 'accordion-2', - active: true + active: true, ), ) ->id('accordion') @@ -1033,8 +1033,8 @@ public function testItemsWithEncodeHeaderAndEncodeBody(): void AccordionItem::to( 'Accordion Item #1', "This is the first item's accordion body.", - 'accordion-1' - ) + 'accordion-1', + ), ) ->id('accordion') ->render(), @@ -1067,8 +1067,8 @@ public function testItemsWithEncodeHeaderAndEncodeBodyWithFalse(): void "This is the first item's accordion body.", 'accordion-1', encodeHeader: false, - encodeBody: false - ) + encodeBody: false, + ), ) ->id('accordion') ->render(), @@ -1125,34 +1125,34 @@ public function testRender(): void ->items( AccordionItem::to( 'Accordion Item #1', - "This is the first item's accordion body." . - ' It is shown by default, until the collapse plugin adds the appropriate classes that we use to style each element. ' . - ' These classes control the overall appearance, as well as the showing and hiding via CSS transitions. ' . - ' You can modify any of this with custom CSS or overriding our default variables. ' . - " It's also worth noting that just about any HTML can go within the .accordion-body, though the transition does limit overflow.", + "This is the first item's accordion body." + . ' It is shown by default, until the collapse plugin adds the appropriate classes that we use to style each element. ' + . ' These classes control the overall appearance, as well as the showing and hiding via CSS transitions. ' + . ' You can modify any of this with custom CSS or overriding our default variables. ' + . " It's also worth noting that just about any HTML can go within the .accordion-body, though the transition does limit overflow.", 'accordion-1', encodeBody: false, - active: true + active: true, ), AccordionItem::to( 'Accordion Item #2', - "This is the second item's accordion body." . - ' It is hidden by default, until the collapse plugin adds the appropriate classes that we use to style each element. ' . - ' These classes control the overall appearance, as well as the showing and hiding via CSS transitions. ' . - ' You can modify any of this with custom CSS or overriding our default variables. ' . - " It's also worth noting that just about any HTML can go within the .accordion-body, though the transition does limit overflow.", + "This is the second item's accordion body." + . ' It is hidden by default, until the collapse plugin adds the appropriate classes that we use to style each element. ' + . ' These classes control the overall appearance, as well as the showing and hiding via CSS transitions. ' + . ' You can modify any of this with custom CSS or overriding our default variables. ' + . " It's also worth noting that just about any HTML can go within the .accordion-body, though the transition does limit overflow.", 'accordion-2', - encodeBody: false + encodeBody: false, ), AccordionItem::to( 'Accordion Item #3', - "This is the third item's accordion body." . - ' It is hidden by default, until the collapse plugin adds the appropriate classes that we use to style each element. ' . - ' These classes control the overall appearance, as well as the showing and hiding via CSS transitions. ' . - ' You can modify any of this with custom CSS or overriding our default variables. ' . - " It's also worth noting that just about any HTML can go within the .accordion-body, though the transition does limit overflow.", + "This is the third item's accordion body." + . ' It is hidden by default, until the collapse plugin adds the appropriate classes that we use to style each element. ' + . ' These classes control the overall appearance, as well as the showing and hiding via CSS transitions. ' + . ' You can modify any of this with custom CSS or overriding our default variables. ' + . " It's also worth noting that just about any HTML can go within the .accordion-body, though the transition does limit overflow.", 'accordion-3', - encodeBody: false + encodeBody: false, ), ) ->id('accordion') diff --git a/tests/AlertTest.php b/tests/AlertTest.php index 2dfb0816c..99d7819be 100644 --- a/tests/AlertTest.php +++ b/tests/AlertTest.php @@ -14,6 +14,8 @@ use Yiisoft\Bootstrap5\Tests\Support\Assert; use Yiisoft\Bootstrap5\Utility\BackgroundColor; +use const PHP_EOL; + /** * Tests for `Alert` widget. */ @@ -559,8 +561,8 @@ public function testRenderLink(): void HTML, Alert::widget() ->body( - 'A simple warning alert with ' . - 'an example link. Give it a click if you like.', + 'A simple warning alert with ' + . 'an example link. Give it a click if you like.', false, ) ->id(false) @@ -584,10 +586,10 @@ public function testRenderIcon(): void Alert::widget() ->addClass('d-flex align-items-center') ->body( - '' . - '' . - '' . PHP_EOL . - '
An example alert with an icon
', + '' + . '' + . '' . PHP_EOL + . '
An example alert with an icon
', false, ) ->id(false) diff --git a/tests/ButtonGroupTest.php b/tests/ButtonGroupTest.php index aca4ac752..4b07fa1ad 100644 --- a/tests/ButtonGroupTest.php +++ b/tests/ButtonGroupTest.php @@ -341,7 +341,7 @@ public function testIdWithSetAttributes(): void Button::widget()->id(false)->label('Button B'), Button::widget()->id(false)->label('Button A')->variant(ButtonVariant::PRIMARY), ) - ->render() + ->render(), ); } diff --git a/tests/ButtonTest.php b/tests/ButtonTest.php index b1464c07d..804598961 100644 --- a/tests/ButtonTest.php +++ b/tests/ButtonTest.php @@ -18,6 +18,8 @@ use Yiisoft\Html\Tag\Div; use Yiisoft\Html\Tag\Span; +use const PHP_EOL; + /** * Tests for `Button` widget */ @@ -711,7 +713,7 @@ public function testTypeInputSubmit(): void * @see https://getbootstrap.com/docs/5.3/components/buttons/#outline-buttons */ #[DataProviderExternal(ButtonProvider::class, 'variant')] - public function testVariant(ButtonVariant|null $buttonVariant, string $expected): void + public function testVariant(?ButtonVariant $buttonVariant, string $expected): void { $variant = $buttonVariant->value ?? 'button'; diff --git a/tests/ButtonToolbarTest.php b/tests/ButtonToolbarTest.php index 31788adf0..cf93ef990 100644 --- a/tests/ButtonToolbarTest.php +++ b/tests/ButtonToolbarTest.php @@ -518,7 +518,7 @@ public function testTag(): void 'aria-label' => 'Input group example', 'aria-describedby' => 'btnGroupAddon', 'placeholder' => 'Input group example', - ] + ], ) ->class('form-control'), "\n", diff --git a/tests/CarouselItemTest.php b/tests/CarouselItemTest.php index c6009d4dc..6dbdbe66e 100644 --- a/tests/CarouselItemTest.php +++ b/tests/CarouselItemTest.php @@ -115,7 +115,7 @@ public function testGetContent(): void public function testGetContentWithStringable(): void { $carouselItem = CarouselItem::to( - new class () implements Stringable { + new class implements Stringable { public function __toString(): string { return 'First slide'; diff --git a/tests/CarouselTest.php b/tests/CarouselTest.php index fad5cd5ec..f587db433 100644 --- a/tests/CarouselTest.php +++ b/tests/CarouselTest.php @@ -519,7 +519,7 @@ public function testCaptionTagNameEmpty(): void { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage( - 'The "captionTagName" and "captionPlaceholderTagName" properties cannot be empty.' + 'The "captionTagName" and "captionPlaceholderTagName" properties cannot be empty.', ); Carousel::widget() @@ -539,7 +539,7 @@ public function testCaptionPlaceholderTagNameEmpty(): void { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage( - 'The "captionTagName" and "captionPlaceholderTagName" properties cannot be empty.' + 'The "captionTagName" and "captionPlaceholderTagName" properties cannot be empty.', ); Carousel::widget() diff --git a/tests/CollapseTest.php b/tests/CollapseTest.php index 4320f9c23..8c1fbd540 100644 --- a/tests/CollapseTest.php +++ b/tests/CollapseTest.php @@ -287,8 +287,8 @@ public function testExample(): void Collapse::widget() ->items( Toggler::for( - 'Some placeholder content for the collapse component. ' . - 'This panel is hidden by default but revealed when the user activates the relevant trigger.', + 'Some placeholder content for the collapse component. ' + . 'This panel is hidden by default but revealed when the user activates the relevant trigger.', 'collapseExample', togglerContent: 'Link with href', togglerAsLink: true, @@ -327,8 +327,8 @@ public function testHorizontal(): void ->containerAttributes(['style' => 'min-height: 120px;']) ->items( Toggler::for( - 'This is some placeholder content for a horizontal collapse. ' . - "It's hidden by default and shown when triggered.", + 'This is some placeholder content for a horizontal collapse. ' + . "It's hidden by default and shown when triggered.", 'collapseExample', togglerContent: 'Toggle width collapse', ), @@ -386,15 +386,15 @@ public function testMultipleTogglesAndTargets(): void ->containerAttributes(['class' => 'row']) ->items( Toggler::for( - 'Some placeholder content for the first collapse component of this multi-collapse example. ' . - 'This panel is hidden by default but revealed when the user activates the relevant trigger.', + 'Some placeholder content for the first collapse component of this multi-collapse example. ' + . 'This panel is hidden by default but revealed when the user activates the relevant trigger.', 'multiCollapseExample1', togglerContent: 'Toggle first element', togglerAsLink: true, ), Toggler::for( - 'Some placeholder content for the second collapse component of this multi-collapse example. ' . - 'This panel is hidden by default but revealed when the user activates the relevant trigger.', + 'Some placeholder content for the second collapse component of this multi-collapse example. ' + . 'This panel is hidden by default but revealed when the user activates the relevant trigger.', 'multiCollapseExample2', togglerContent: 'Toggle second element', ), diff --git a/tests/DropdownTest.php b/tests/DropdownTest.php index 5c37e1929..3847962ba 100644 --- a/tests/DropdownTest.php +++ b/tests/DropdownTest.php @@ -1229,7 +1229,7 @@ public function testDropdownItemWithListContent(): void DropdownItem::listContent( <<WhatsApp - HTML + HTML, ), ) ->render(), @@ -1877,7 +1877,7 @@ public function testToggler(): void ], ) ->addClass('btn btn-primary dropdown-toggle') - ->content('Dropdown custom button') + ->content('Dropdown custom button'), ) ->render(), ); diff --git a/tests/NavBarTest.php b/tests/NavBarTest.php index 9062b202c..1f6a65ed5 100644 --- a/tests/NavBarTest.php +++ b/tests/NavBarTest.php @@ -328,7 +328,7 @@ public function testBrandAttributes(): void NavBar::widget()->brandText('NavBar') ->brandAttributes(['class' => 'test-class']) ->id('navbar') - ->begin() + ->begin(), ) . NavBar::end(), ); } @@ -409,7 +409,7 @@ public function testBrandAsImage(): void ) ->brandUrl('#') ->id('navbar') - ->begin() + ->begin(), ) . NavBar::end(), ); } @@ -441,11 +441,11 @@ public function testBrandAsImageWithStringable(): void ->alt('bootstrap') ->height(24) ->src('/docs/5.3/assets/brand/bootstrap-logo.svg') - ->width(30) + ->width(30), ) ->brandUrl('#') ->id('navbar') - ->begin() + ->begin(), ) . NavBar::end(), ); } @@ -484,7 +484,7 @@ public function testBrandAsImageAndText(): void ->brandText('NavBar') ->brandUrl('#') ->id('navbar') - ->begin() + ->begin(), ) . NavBar::end(), ); } @@ -527,7 +527,7 @@ public function testClass(): void ->addClass('test-class') ->class('custom-class', 'another-class', BackgroundColor::PRIMARY) ->id('navbar') - ->begin() + ->begin(), ) . NavBar::end(), ); } @@ -558,7 +558,7 @@ public function testContainer(): void ->containerAttributes(['class' => 'container']) ->brandText('NavBar') ->id('navbar') - ->begin() + ->begin(), ) . NavBar::end(), ); } @@ -586,7 +586,7 @@ public function testContainerResponsive(): void ->brandText('NavBar') ->innerContainerAttributes(['class' => 'container-md']) ->id('navbar') - ->begin() + ->begin(), ) . NavBar::end(), ); } @@ -614,7 +614,7 @@ public function testExpandWithSm(): void ->brandText('NavBar') ->expand(NavBarExpand::SM) ->id('navbar') - ->begin() + ->begin(), ) . NavBar::end(), ); } @@ -642,7 +642,7 @@ public function testExpandWithMd(): void ->brandText('NavBar') ->expand(NavBarExpand::MD) ->id('navbar') - ->begin() + ->begin(), ) . NavBar::end(), ); } @@ -670,7 +670,7 @@ public function testExpandWithLg(): void ->brandText('NavBar') ->expand(NavBarExpand::LG) ->id('navbar') - ->begin() + ->begin(), ) . NavBar::end(), ); } @@ -698,7 +698,7 @@ public function testExpandWithXl(): void ->brandText('NavBar') ->expand(NavBarExpand::XL) ->id('navbar') - ->begin() + ->begin(), ) . NavBar::end(), ); } @@ -726,7 +726,7 @@ public function testExpandWithXxl(): void ->brandText('NavBar') ->expand(NavBarExpand::XXL) ->id('navbar') - ->begin() + ->begin(), ) . NavBar::end(), ); } @@ -842,7 +842,7 @@ public function testPlacementWithFixedBottom(): void ->brandText('NavBar') ->id('navbar') ->placement(NavBarPlacement::FIXED_BOTTOM) - ->begin() + ->begin(), ) . NavBar::end(), ); } @@ -870,7 +870,7 @@ public function testPlacementWithFixedTop(): void ->brandText('NavBar') ->id('navbar') ->placement(NavBarPlacement::FIXED_TOP) - ->begin() + ->begin(), ) . NavBar::end(), ); } @@ -898,7 +898,7 @@ public function testPlacementWithStickyBottom(): void ->brandText('NavBar') ->id('navbar') ->placement(NavBarPlacement::STICKY_BOTTOM) - ->begin() + ->begin(), ) . NavBar::end(), ); } @@ -923,7 +923,7 @@ public function testPlacementWithStickyTop(): void ->brandText('NavBar') ->id('navbar') ->placement(NavBarPlacement::STICKY_TOP) - ->begin() + ->begin(), ), ); } @@ -1003,8 +1003,8 @@ public function testRender(): void ->brandText('NavBar') ->brandUrl('#') ->id('navbarSupportedContent') - ->begin() . - Nav::widget() + ->begin() + . Nav::widget() ->currentPath('/home') ->items( NavLink::to('Home', '/home'), @@ -1020,8 +1020,8 @@ public function testRender(): void NavLink::to('Disabled', '#', disabled: true), ) ->styles(NavStyle::NAVBAR) - ->render() . - NavBar::end(), + ->render() + . NavBar::end(), ); } diff --git a/tests/OffcanvasTest.php b/tests/OffcanvasTest.php index 600134ad2..46271a680 100644 --- a/tests/OffcanvasTest.php +++ b/tests/OffcanvasTest.php @@ -17,6 +17,8 @@ use Yiisoft\Html\Tag\Button; use Yiisoft\Html\Tag\Div; +use const PHP_EOL; + #[Group('offcanvas')] final class OffcanvasTest extends TestCase { @@ -39,8 +41,8 @@ public function testAddAttributes(): void ->id('offcanvasExample') ->title('Offcanvas') ->togglerContent('Button with data-bs-target') - ->begin() . - Offcanvas::end(), + ->begin() + . Offcanvas::end(), ); } @@ -178,8 +180,8 @@ public function testAddTogglerAttribute(): void Offcanvas::widget() ->addTogglerAttribute('data-id', '123') ->id('offcanvasExample') - ->togglerContent('Toggler')->begin() . - Offcanvas::end(), + ->togglerContent('Toggler')->begin() + . Offcanvas::end(), ); } @@ -315,8 +317,8 @@ public function testAttribute(): void ->attribute('data-id', '123') ->id('offcanvasExample') ->togglerContent('Toggler') - ->begin() . - Offcanvas::end(), + ->begin() + . Offcanvas::end(), ); } @@ -339,8 +341,8 @@ public function testAttributes(): void ->id('offcanvasExample') ->title('Offcanvas') ->togglerContent('Button with data-bs-target') - ->begin() . - Offcanvas::end(), + ->begin() + . Offcanvas::end(), ); } @@ -364,10 +366,10 @@ public function testBodyAttributes(): void ->id('offcanvas') ->title('Offcanvas') ->togglerContent('Toggle Offcanvas') - ->begin() . - 'Content for the offcanvas goes here. You can place just about any Bootstrap component or custom ' . - 'elements here.' . "\n" . - Offcanvas::end(), + ->begin() + . 'Content for the offcanvas goes here. You can place just about any Bootstrap component or custom ' + . 'elements here.' . "\n" + . Offcanvas::end(), ); } @@ -394,9 +396,9 @@ public function testBodyScrolling(): void ->scrollable() ->title('Offcanvas with body scrolling') ->togglerContent('Enable body scrolling') - ->begin() . - '

Try scrolling the rest of the page to see this option in action.

' . PHP_EOL . - Offcanvas::end(), + ->begin() + . '

Try scrolling the rest of the page to see this option in action.

' . PHP_EOL + . Offcanvas::end(), ); } @@ -424,9 +426,9 @@ public function testBodyScrollingAndBackdrop(): void ->scrollable() ->title('Backdrop with scrolling') ->togglerContent('Enable both scrolling & backdrop') - ->begin() . - '

Try scrolling the rest of the page to see this option in action.

' . PHP_EOL . - Offcanvas::end(), + ->begin() + . '

Try scrolling the rest of the page to see this option in action.

' . PHP_EOL + . Offcanvas::end(), ); } @@ -450,8 +452,8 @@ public function testClass(): void ->id('offcanvasExample') ->title('Offcanvas') ->togglerContent('Button with data-bs-target') - ->begin() . - Offcanvas::end(), + ->begin() + . Offcanvas::end(), ); } @@ -475,8 +477,8 @@ public function testHeaderAttributes(): void ->id('offcanvasExample') ->title('Offcanvas') ->togglerContent('Button with data-bs-target') - ->begin() . - Offcanvas::end(), + ->begin() + . Offcanvas::end(), ); } @@ -498,8 +500,8 @@ public function testIdWithSetAttributes(): void ->addAttributes(['id' => 'offcanvasExample']) ->title('Offcanvas') ->togglerContent('Button with data-bs-target') - ->begin() . - Offcanvas::end(), + ->begin() + . Offcanvas::end(), ); } @@ -554,8 +556,8 @@ public function testPlacementWithBottom(): void ->placement(OffcanvasPlacement::BOTTOM) ->title('Offcanvas') ->togglerContent('Toggle bottom offcanvas') - ->begin() . - Offcanvas::end(), + ->begin() + . Offcanvas::end(), ); } @@ -581,8 +583,8 @@ public function testPlacementWithEnd(): void ->placement(OffcanvasPlacement::END) ->title('Offcanvas') ->togglerContent('Toggle end offcanvas') - ->begin() . - Offcanvas::end(), + ->begin() + . Offcanvas::end(), ); } @@ -608,8 +610,8 @@ public function testPlacementWithStart(): void ->placement(OffcanvasPlacement::START) ->title('Offcanvas') ->togglerContent('Toggle start offcanvas') - ->begin() . - Offcanvas::end(), + ->begin() + . Offcanvas::end(), ); } @@ -635,8 +637,8 @@ public function testPlacementWithTop(): void ->placement(OffcanvasPlacement::TOP) ->title('Offcanvas') ->togglerContent('Toggle top offcanvas') - ->begin() . - Offcanvas::end(), + ->begin() + . Offcanvas::end(), ); } @@ -678,21 +680,21 @@ public function testRender(): void ->id('offcanvasExample') ->title('Offcanvas') ->togglerContent('Button with data-bs-target') - ->begin() . - Div::tag()->content( + ->begin() + . Div::tag()->content( "\n", 'Some text as placeholder. In real life you can have the elements you have chosen. Like, text, images, lists, etc.', "\n", - ) . PHP_EOL . - Dropdown::widget() + ) . PHP_EOL + . Dropdown::widget() ->addClass('mt-3') ->items( DropdownItem::link('Action', '#'), DropdownItem::link('Another action', '#'), DropdownItem::link('Something else here', '#'), ) - ->render() . PHP_EOL . - Offcanvas::end(), + ->render() . PHP_EOL + . Offcanvas::end(), ); } @@ -720,9 +722,9 @@ public function testResponsiveWithSM(): void ->responsive(Responsive::SM) ->title('Offcanvas on small devices') ->togglerContent('Toggle offcanvas on small devices') - ->begin() . - '

On small devices this will take up the entire screen.

' . PHP_EOL . - Offcanvas::end(), + ->begin() + . '

On small devices this will take up the entire screen.

' . PHP_EOL + . Offcanvas::end(), ); } @@ -750,9 +752,9 @@ public function testResponsiveWithMD(): void ->responsive(Responsive::MD) ->title('Offcanvas on medium devices') ->togglerContent('Toggle offcanvas on medium devices') - ->begin() . - '

On medium devices this will take up the entire screen.

' . PHP_EOL . - Offcanvas::end(), + ->begin() + . '

On medium devices this will take up the entire screen.

' . PHP_EOL + . Offcanvas::end(), ); } @@ -780,9 +782,9 @@ public function testResponsiveWithLG(): void ->responsive(Responsive::LG) ->title('Offcanvas on large devices') ->togglerContent('Toggle offcanvas on large devices') - ->begin() . - '

On large devices this will take up the entire screen.

' . PHP_EOL . - Offcanvas::end(), + ->begin() + . '

On large devices this will take up the entire screen.

' . PHP_EOL + . Offcanvas::end(), ); } @@ -810,9 +812,9 @@ public function testResponsiveWithXL(): void ->responsive(Responsive::XL) ->title('Offcanvas on extra large devices') ->togglerContent('Toggle offcanvas on extra large devices') - ->begin() . - '

On extra large devices this will take up the entire screen.

' . PHP_EOL . - Offcanvas::end(), + ->begin() + . '

On extra large devices this will take up the entire screen.

' . PHP_EOL + . Offcanvas::end(), ); } @@ -840,9 +842,9 @@ public function testResponsiveWithXXL(): void ->responsive(Responsive::XXL) ->title('Offcanvas on extra extra large devices') ->togglerContent('Toggle offcanvas on extra extra large devices') - ->begin() . - '

On extra extra large devices this will take up the entire screen.

' . PHP_EOL . - Offcanvas::end(), + ->begin() + . '

On extra extra large devices this will take up the entire screen.

' . PHP_EOL + . Offcanvas::end(), ); } @@ -868,10 +870,10 @@ public function testShow(): void ->show() ->title('Offcanvas') ->togglerContent('Toggle Offcanvas') - ->begin() . - 'Content for the offcanvas goes here. You can place just about any Bootstrap component or custom ' . - 'elements here.' . "\n" . - Offcanvas::end(), + ->begin() + . 'Content for the offcanvas goes here. You can place just about any Bootstrap component or custom ' + . 'elements here.' . "\n" + . Offcanvas::end(), ); } @@ -898,9 +900,9 @@ public function testStaticBackdrop(): void ->backdropStatic() ->title('Offcanvas') ->togglerContent('Toggle static offcanvas') - ->begin() . - '
I will not close if you click outside of me.
' . PHP_EOL . - Offcanvas::end(), + ->begin() + . '
I will not close if you click outside of me.
' . PHP_EOL + . Offcanvas::end(), ); } @@ -922,8 +924,8 @@ public function testTitle(): void ->id('offcanvasExample') ->title('Custom title') ->togglerContent('Button with data-bs-target') - ->begin() . - Offcanvas::end(), + ->begin() + . Offcanvas::end(), ); } @@ -946,8 +948,8 @@ public function testTitleAttributes(): void ->title('Custom title') ->titleAttributes(['data-id' => '123']) ->togglerContent('Button with data-bs-target') - ->begin() . - Offcanvas::end(), + ->begin() + . Offcanvas::end(), ); } @@ -974,9 +976,9 @@ public function testThemeDark(): void ->theme('dark') ->title('Offcanvas') ->togglerContent('Toggle dark offcanvas') - ->begin() . - '
Dark offcanvas content.
' . PHP_EOL . - Offcanvas::end(), + ->begin() + . '
Dark offcanvas content.
' . PHP_EOL + . Offcanvas::end(), ); } @@ -1003,9 +1005,9 @@ public function testThemeLight(): void ->theme('light') ->title('Offcanvas') ->togglerContent('Toggle light offcanvas') - ->begin() . - '
Light offcanvas content.
' . PHP_EOL . - Offcanvas::end(), + ->begin() + . '
Light offcanvas content.
' . PHP_EOL + . Offcanvas::end(), ); } @@ -1043,8 +1045,8 @@ public function testTogglerContent(): void ->id('offcanvasExample') ->title('Offcanvas') ->togglerContent('Toggle offcanvas') - ->begin() . - Offcanvas::end(), + ->begin() + . Offcanvas::end(), ); } @@ -1067,8 +1069,8 @@ public function testTogglerAttributes(): void ->title('Offcanvas') ->togglerContent('Toggle offcanvas') ->togglerAttributes(['data-id' => '123']) - ->begin() . - Offcanvas::end(), + ->begin() + . Offcanvas::end(), ); } @@ -1089,8 +1091,8 @@ public function testTogglerWithStringable(): void Offcanvas::widget() ->id('offcanvasExample') ->toggler(Button::tag()->addClass('btn btn-primary')->content('Toggle offcanvas')) - ->begin() . - Offcanvas::end(), + ->begin() + . Offcanvas::end(), ); } }