Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
## 3.11.1 under development

- New #249: Add `Tag::addStyle()` and `Tag::removeStyle()` methods (@vjik)
- New #252: Add `Color` class, `Html::color()` and `Input::color()` methods (@razvbir)

## 3.11.0 June 10, 2025

Expand Down
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ The package provides various tools to help with dynamic server-side generation o

- Tag classes `A`, `Address`, `Article`, `Aside`, `Audio`, `B`, `Body`, `Br`, `Button`, `Caption`, `Col`, `Colgroup`,
`Datalist`, `Div`, `Em`, `Fieldset`, `Footer`, `Form`, `H1`, `H2`, `H3`, `H4`, `H5`, `H6`, `Header`, `Hr`, `Hgroup`,
`Html`, `I`, `Img`, `Input` (and specialized `Checkbox`, `Radio`, `Range`, `File`), `Label`, `Legend`, `Li`, `Link`,
`Html`, `I`, `Img`, `Input` (and specialized `Checkbox`, `Radio`, `Range`, `File`, `Color`), `Label`, `Legend`, `Li`, `Link`,
`Meta`, `Nav`, `Noscript`, `Ol`, `Optgroup`, `Option`, `P`, `Picture`, `Script`, `Section`, `Select`, `Small`,
`Source`, `Span`, `Strong`, `Style`, `Table`, `Tbody`, `Td`, `Textarea`, `Tfoot`, `Th`, `Thead`, `Title`, `Tr`,
`Track`, `Ul`, `Video`.
Expand Down Expand Up @@ -319,9 +319,10 @@ Overall the helper has the following method groups.
- button
- buttonInput
- checkbox
- file
- color
- datalist
- fieldset
- file
- fileInput
- form
- hiddenInput
Expand All @@ -332,13 +333,14 @@ Overall the helper has the following method groups.
- option
- passwordInput
- radio
- range
- resetButton
- resetInput
- select
- submitButton
- submitInput
- textInput
- textarea
- textInput

#### Table tags

Expand Down
19 changes: 19 additions & 0 deletions src/Html.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
use Yiisoft\Html\Tag\Img;
use Yiisoft\Html\Tag\Input;
use Yiisoft\Html\Tag\Input\Checkbox;
use Yiisoft\Html\Tag\Input\Color;
use Yiisoft\Html\Tag\Input\File;
use Yiisoft\Html\Tag\Input\Radio;
use Yiisoft\Html\Tag\Input\Range;
Expand Down Expand Up @@ -877,6 +878,24 @@
return $attributes === [] ? $tag : $tag->addAttributes($attributes);
}

/**
* Generates a color {@see Input} field.
*
* @see Input::color()
*
* @param string|null $name The name attribute.
* @param string|Stringable|null $value The value attribute.
* @param array $attributes The tag attributes in terms of name-value pairs.
*/
public static function color(
?string $name = null,
string|Stringable|null $value = null,
array $attributes = []
): Color {
$tag = Input::color($name, $value);
return $attributes === [] ? $tag : $tag->addAttributes($attributes);
}

/**
* Generates a checkbox {@see Input}.
*
Expand Down Expand Up @@ -1649,7 +1668,7 @@
*/
public static function renderTagAttributes(array $attributes): string
{
if (count($attributes) > 1) {

Check warning on line 1671 in src/Html.php

View workflow job for this annotation

GitHub Actions / mutation / PHP 8.4-ubuntu-latest

Escaped Mutant for Mutator "GreaterThan": @@ @@ */ public static function renderTagAttributes(array $attributes): string { - if (count($attributes) > 1) { + if (count($attributes) >= 1) { $sorted = []; foreach (self::ATTRIBUTE_ORDER as $name) { if (isset($attributes[$name])) {
$sorted = [];
foreach (self::ATTRIBUTE_ORDER as $name) {
if (isset($attributes[$name])) {
Expand All @@ -1673,11 +1692,11 @@
/** @psalm-var array<array-key, scalar[]|string|Stringable|null> $value */
foreach ($value as $n => $v) {
if (!isset($v)) {
continue;

Check warning on line 1695 in src/Html.php

View workflow job for this annotation

GitHub Actions / mutation / PHP 8.4-ubuntu-latest

Escaped Mutant for Mutator "Continue_": @@ @@ /** @psalm-var array<array-key, scalar[]|string|Stringable|null> $value */ foreach ($value as $n => $v) { if (!isset($v)) { - continue; + break; } $fullName = "{$name}-{$n}"; if (in_array($fullName, self::ATTRIBUTES_WITH_CONCATENATED_VALUES, true)) {
}
$fullName = "$name-$n";
if (in_array($fullName, self::ATTRIBUTES_WITH_CONCATENATED_VALUES, true)) {
$html .= self::renderAttribute(

Check warning on line 1699 in src/Html.php

View workflow job for this annotation

GitHub Actions / mutation / PHP 8.4-ubuntu-latest

Escaped Mutant for Mutator "Assignment": @@ @@ } $fullName = "{$name}-{$n}"; if (in_array($fullName, self::ATTRIBUTES_WITH_CONCATENATED_VALUES, true)) { - $html .= self::renderAttribute($fullName, self::encodeAttribute(is_array($v) ? implode(' ', $v) : $v)); + $html = self::renderAttribute($fullName, self::encodeAttribute(is_array($v) ? implode(' ', $v) : $v)); } else { $html .= is_array($v) ? self::renderAttribute($fullName, Json::htmlEncode($v), '\'') : self::renderAttribute($fullName, self::encodeAttribute($v)); }
$fullName,
self::encodeAttribute(
is_array($v) ? implode(' ', $v) : $v,
Expand Down Expand Up @@ -1803,7 +1822,7 @@
}
} else {
/** @var string[] */
$classes = preg_split('/\s+/', (string) $options['class'], -1, PREG_SPLIT_NO_EMPTY);

Check warning on line 1825 in src/Html.php

View workflow job for this annotation

GitHub Actions / mutation / PHP 8.4-ubuntu-latest

Escaped Mutant for Mutator "CastString": @@ @@ } } else { /** @var string[] */ - $classes = preg_split('/\s+/', (string) $options['class'], -1, PREG_SPLIT_NO_EMPTY); + $classes = preg_split('/\s+/', $options['class'], -1, PREG_SPLIT_NO_EMPTY); $classes = array_diff($classes, (array) $class); if (empty($classes)) { unset($options['class']);
$classes = array_diff($classes, (array) $class);
if (empty($classes)) {
unset($options['class']);
Expand Down Expand Up @@ -1956,7 +1975,7 @@
public static function cssStyleToArray(string|Stringable $style): array
{
$result = [];
foreach (explode(';', (string) $style) as $property) {

Check warning on line 1978 in src/Html.php

View workflow job for this annotation

GitHub Actions / mutation / PHP 8.4-ubuntu-latest

Escaped Mutant for Mutator "CastString": @@ @@ public static function cssStyleToArray(string|Stringable $style): array { $result = []; - foreach (explode(';', (string) $style) as $property) { + foreach (explode(';', $style) as $property) { $property = explode(':', $property); if (count($property) > 1) { $result[trim($property[0])] = trim($property[1]);
$property = explode(':', $property);
if (count($property) > 1) {
$result[trim($property[0])] = trim($property[1]);
Expand Down
21 changes: 21 additions & 0 deletions src/Tag/Input.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use Stringable;
use Yiisoft\Html\Tag\Base\InputTag;
use Yiisoft\Html\Tag\Input\Checkbox;
use Yiisoft\Html\Tag\Input\Color;
use Yiisoft\Html\Tag\Input\File;
use Yiisoft\Html\Tag\Input\Radio;
use Yiisoft\Html\Tag\Input\Range;
Expand Down Expand Up @@ -149,6 +150,26 @@ public static function range(?string $name = null, float|int|string|Stringable|n
return $input;
}

/**
* Color.
*
* @link https://html.spec.whatwg.org/multipage/input.html#color-state-(type=color)
*
* @param string|null $name Name of the input.
* @param string|Stringable|null $value Value of the input.
*/
public static function color(?string $name = null, string|Stringable|null $value = null): Color
{
$input = Color::tag();
if ($name !== null) {
$input = $input->name($name);
}
if ($value !== null) {
$input = $input->value($value);
}
return $input;
}

/**
* Button.
*
Expand Down
18 changes: 18 additions & 0 deletions src/Tag/Input/Color.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

declare(strict_types=1);

namespace Yiisoft\Html\Tag\Input;

use Yiisoft\Html\Tag\Base\InputTag;

/**
* @link https://html.spec.whatwg.org/multipage/input.html#color-state-(type=color)
*/
final class Color extends InputTag
{
protected function prepareAttributes(): void
{
$this->attributes['type'] = 'color';
}
}
16 changes: 16 additions & 0 deletions tests/HtmlTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,22 @@ public function testTextInput(): void
);
}

public function testColorInput(): void
{
$this->assertSame('<input type="color">', Html::color()->render());
$this->assertSame('<input type="color" name>', Html::color('')->render());
$this->assertSame('<input type="color" value>', Html::color(null, '')->render());
$this->assertSame('<input type="color" name="test">', Html::color('test')->render());
$this->assertSame(
'<input type="color" name="test" value="#ff0000">',
Html::color('test', '#ff0000')->render(),
);
$this->assertSame(
'<input type="color" name="test" value="#ff0000" required>',
Html::color('test', '#ff0000', ['required' => true])->render(),
);
}

public function testHiddenInput(): void
{
$this->assertSame('<input type="hidden">', Html::hiddenInput()->render());
Expand Down
22 changes: 22 additions & 0 deletions tests/Tag/Input/ColorTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

declare(strict_types=1);

namespace Yiisoft\Html\Tests\Tag\Input;

use PHPUnit\Framework\TestCase;
use Yiisoft\Html\Tag\Input\Color;

final class ColorTest extends TestCase
{
public function testBase(): void
{
$this->assertSame(
'<input type="color" name="color" value="#ff0000">',
Color::tag()
->name('color')
->value('#ff0000')
->render()
);
}
}
8 changes: 8 additions & 0 deletions tests/Tag/InputTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,14 @@ public function testRange(): void
);
}

public function testColor(): void
{
$this->assertSame(
'<input type="color" name="color" value="#ff0000">',
(string) Input::color('color', '#ff0000')
);
}

public function testButton(): void
{
$this->assertSame(
Expand Down
Loading