From 19545a6aa5aff35fa51c101f2e4ef338272175cd Mon Sep 17 00:00:00 2001 From: Josh Bruce Date: Thu, 15 Oct 2026 11:40:46 -0400 Subject: [PATCH 1/2] BC: Update all form components to date Fixes #47 --- src/Forms/EmailInput.php | 23 ++++--- src/Forms/Password.php | 115 ++++++++++++++++++++++------------- src/Forms/TextArea.php | 30 ++++----- src/Forms/TextInput.php | 30 ++++----- tests/Forms/PasswordTest.php | 10 +-- 5 files changed, 126 insertions(+), 82 deletions(-) diff --git a/src/Forms/EmailInput.php b/src/Forms/EmailInput.php index 4e3b4ee..2601092 100644 --- a/src/Forms/EmailInput.php +++ b/src/Forms/EmailInput.php @@ -80,31 +80,40 @@ public function content(string|Stringable ...$content): self return $this; } - private function warningMessage(string $warningId): string|PropertyInterface + private function warningMessage(): string { if ($this->warningMessage === '') { return ''; } if (is_string($this->warningMessage)) { - return Element::p($this->warningMessage)->props( - 'id ' . $warningId + return (string) Element::p($this->warningMessage)->props( + 'id ' . $this->id . '-warning' ); } $warning = clone $this->warningMessage; - return $warning->prop('id ' . $warningId); + return (string) $warning->prop('id ' . $this->id . '-warning'); } - public function __toString(): string + /** + * @return list + */ + private function inputProperties(bool $noWarning): array { - $inputProperties = $this->warningMessage === '' + return ($noWarning) ? $this->inputProperties : ControlProperties::withWarning( - array_values($this->inputProperties), + $this->inputProperties, $this->id . '-warning' ); + } + + public function __toString(): string + { + $warning = self::warningMessage(); + $inputProperties = self::inputProperties($warning === ''); $input = Element::input()->omitEndTag()->props(...[ ...$inputProperties, diff --git a/src/Forms/Password.php b/src/Forms/Password.php index 825493b..be3cf23 100644 --- a/src/Forms/Password.php +++ b/src/Forms/Password.php @@ -12,11 +12,12 @@ class Password implements Stringable { - // phpcs:disable - private string $warningId { - get => $this->name . '-warning'; - } - // phpcs:enable + private string $id; + + /** + * @var string[] + */ + private array $wrapperProperties = []; /** * @var string[] @@ -28,6 +29,10 @@ class Password implements Stringable */ private array $inputProperties = []; + /** + * @var array + */ + private array $content = []; private PasswordAutocomplete $autocomplete = PasswordAutocomplete::CurrentPassword; @@ -44,81 +49,107 @@ final private function __construct( private readonly string|Stringable $name, private readonly string|PropertyInterface $warningMessage = '' ) { + $this->id = $name; } - public function labelProps(string ...$properties): self + public function id(string $id): self { - $this->labelProperties = $properties; + $this->id = $id; return $this; } - public function inputProps(string ...$properties): self + public function wrapperProps(string ...$properties): self { - $this->inputProperties = $properties; + $this->wrapperProperties = $properties; return $this; } - public function forNewPassword(): self + public function labelProps(string ...$properties): self { - $this->autocomplete = PasswordAutocomplete::NewPassword; + $this->labelProperties = $properties; return $this; } - public function autocompleteOff(): self + public function inputProps(string ...$properties): self { - $this->autocomplete = PasswordAutocomplete::Off; + $this->inputProperties = $properties; return $this; } - public function autocompleteOn(): self + public function content(string|Stringable ...$content): self { - $this->autocomplete = PasswordAutocomplete::On; + $this->content = $content; return $this; } - private function warningMessage(): string|PropertyInterface + private function warningMessage(): string { if ($this->warningMessage === '') { return ''; } if (is_string($this->warningMessage)) { - return Element::p($this->warningMessage)->props( - 'id ' . $this->warningId + return (string) Element::p($this->warningMessage)->props( + 'id ' . $this->id . '-warning' ); } - return $this->warningMessage->prop('id ' . $this->warningId); + $warning = clone $this->warningMessage; + + return (string) $warning->prop('id ' . $this->id . '-warning'); + } + + /** + * @return list + */ + private function inputProperties(bool $noWarning): array + { + return ($noWarning) + ? $this->inputProperties + : ControlProperties::withWarning( + $this->inputProperties, + $this->id . '-warning' + ); + } + + public function forNewPassword(): self + { + $this->autocomplete = PasswordAutocomplete::NewPassword; + return $this; + } + + public function autocompleteOff(): self + { + $this->autocomplete = PasswordAutocomplete::Off; + return $this; + } + + public function autocompleteOn(): self + { + $this->autocomplete = PasswordAutocomplete::On; + return $this; } public function __toString(): string { - $elements = []; - $elements[] = Element::label($this->label)->props( - 'for ' . $this->name, - ...$this->labelProperties - ); + $warning = self::warningMessage(); + $inputProperties = self::inputProperties($warning === ''); - $input = Element::input()->omitEndTag()->props( + $input = Element::input()->omitEndTag()->props(...[ + ...$inputProperties, 'type password', - 'id ' . $this->name, + 'id ' . $this->id, 'name ' . $this->name, 'autocomplete ' . $this->autocomplete->value, - ...$this->inputProperties - ); - - $warningMessage = self::warningMessage(); - $hasWarningMessage = ($warningMessage !== ''); - if ($hasWarningMessage) { - $input = $input->prop('aria-invalid true'); - $input = $input->prop('aria-describedby ' . $this->warningId); - } - $elements[] = $input; - - if ($hasWarningMessage) { - $elements[] = $warningMessage; - } - - return implode('', array_map('strval', $elements)); + ]); + + return (string) Element::div( + Element::label($this->label)->props(...[ + ...$this->labelProperties, + 'for ' . $this->id + ]), + $input, + ...[...$this->content, $warning] + )->props(...$this->wrapperProperties); } } diff --git a/src/Forms/TextArea.php b/src/Forms/TextArea.php index 7f31420..493415f 100644 --- a/src/Forms/TextArea.php +++ b/src/Forms/TextArea.php @@ -80,31 +80,40 @@ public function content(string|Stringable ...$content): self return $this; } - private function warningMessage(string $warningId): string|PropertyInterface + private function warningMessage(): string { if ($this->warningMessage === '') { return ''; } if (is_string($this->warningMessage)) { - return Element::p($this->warningMessage)->props( - 'id ' . $warningId + return (string) Element::p($this->warningMessage)->props( + 'id ' . $this->id . '-warning' ); } $warning = clone $this->warningMessage; - return $warning->prop('id ' . $warningId); + return (string) $warning->prop('id ' . $this->id . '-warning'); } - public function __toString(): string + /** + * @return list + */ + private function inputProperties(bool $noWarning): array { - $inputProperties = $this->warningMessage === '' + return ($noWarning) ? $this->inputProperties : ControlProperties::withWarning( - array_values($this->inputProperties), + $this->inputProperties, $this->id . '-warning' ); + } + + public function __toString(): string + { + $warning = self::warningMessage(); + $inputProperties = self::inputProperties($warning === ''); $textarea = Element::textarea( "\n" . $this->value @@ -114,13 +123,6 @@ public function __toString(): string 'name ' . $this->name ]); - $warning = ''; - if ($this->warningMessage !== '') { - $warningId = $this->id . '-warning'; - - $warning = (string) self::warningMessage($warningId); - } - return (string) Element::div( Element::label($this->label)->props(...[ ...$this->labelProperties, diff --git a/src/Forms/TextInput.php b/src/Forms/TextInput.php index fb473dd..7366275 100644 --- a/src/Forms/TextInput.php +++ b/src/Forms/TextInput.php @@ -80,31 +80,40 @@ public function content(string|Stringable ...$content): self return $this; } - private function warningMessage(string $warningId): string|PropertyInterface + private function warningMessage(): string { if ($this->warningMessage === '') { return ''; } if (is_string($this->warningMessage)) { - return Element::p($this->warningMessage)->props( - 'id ' . $warningId + return (string) Element::p($this->warningMessage)->props( + 'id ' . $this->id . '-warning' ); } $warning = clone $this->warningMessage; - return $warning->prop('id ' . $warningId); + return (string) $warning->prop('id ' . $this->id . '-warning'); } - public function __toString(): string + /** + * @return list + */ + private function inputProperties(bool $noWarning): array { - $inputProperties = $this->warningMessage === '' + return ($noWarning) ? $this->inputProperties : ControlProperties::withWarning( - array_values($this->inputProperties), + $this->inputProperties, $this->id . '-warning' ); + } + + public function __toString(): string + { + $warning = self::warningMessage(); + $inputProperties = self::inputProperties($warning === ''); $input = Element::input()->omitEndTag()->props(...[ ...$inputProperties, @@ -114,13 +123,6 @@ public function __toString(): string 'value ' . $this->value ]); - $warning = ''; - if ($this->warningMessage !== '') { - $warningId = $this->id . '-warning'; - - $warning = (string) self::warningMessage($warningId); - } - return (string) Element::div( Element::label($this->label)->props(...[ ...$this->labelProperties, diff --git a/tests/Forms/PasswordTest.php b/tests/Forms/PasswordTest.php index 00d6bda..e9eb046 100644 --- a/tests/Forms/PasswordTest.php +++ b/tests/Forms/PasswordTest.php @@ -14,7 +14,7 @@ class PasswordTest extends TestCase public function can_set_warning_message(): void // phpcs:ignore { $expected = <<Password

Invalid value

+

Invalid value

html; $result = (string) Password::create( @@ -30,7 +30,7 @@ public function can_set_warning_message(): void // phpcs:ignore public function can_change_autocomplete(): void // phpcs:ignore { $expected = <<Password +
html; $result = (string) Password::create( @@ -41,7 +41,7 @@ public function can_change_autocomplete(): void // phpcs:ignore parent::assertSame($expected, $result); $expected = <<Password +
html; $result = (string) Password::create( @@ -52,7 +52,7 @@ public function can_change_autocomplete(): void // phpcs:ignore parent::assertSame($expected, $result); $expected = <<Password +
html; $result = (string) Password::create( @@ -67,7 +67,7 @@ public function can_change_autocomplete(): void // phpcs:ignore public function is_expected_base(): void // phpcs:ignore { $expected = <<Password +
html; $result = (string) Password::create( From 7afb18c514ec6fcca6e236eba05b0734680e53a6 Mon Sep 17 00:00:00 2001 From: Josh Bruce Date: Thu, 15 Oct 2026 11:56:40 -0400 Subject: [PATCH 2/2] fix: Stan --- src/Forms/EmailInput.php | 23 ++++++++--------------- src/Forms/Password.php | 16 ++++++++-------- src/Forms/TextArea.php | 16 ++++++++-------- src/Forms/TextInput.php | 14 +++++++------- 4 files changed, 31 insertions(+), 38 deletions(-) diff --git a/src/Forms/EmailInput.php b/src/Forms/EmailInput.php index 2601092..b4a8bd6 100644 --- a/src/Forms/EmailInput.php +++ b/src/Forms/EmailInput.php @@ -13,22 +13,22 @@ class EmailInput implements Stringable private string $id; /** - * @var string[] + * @var list */ private array $wrapperProperties = []; /** - * @var string[] + * @var list */ private array $labelProperties = []; /** - * @var string[] + * @var list */ private array $inputProperties = []; /** - * @var array + * @var list */ private array $content = []; @@ -58,25 +58,25 @@ public function id(string $id): self public function wrapperProps(string ...$properties): self { - $this->wrapperProperties = $properties; + $this->wrapperProperties = array_values($properties); return $this; } public function labelProps(string ...$properties): self { - $this->labelProperties = $properties; + $this->labelProperties = array_values($properties); return $this; } public function inputProps(string ...$properties): self { - $this->inputProperties = $properties; + $this->inputProperties = array_values($properties); return $this; } public function content(string|Stringable ...$content): self { - $this->content = $content; + $this->content = array_values($content); return $this; } @@ -125,13 +125,6 @@ public function __toString(): string 'autocorrect off' ]); - $warning = ''; - if ($this->warningMessage !== '') { - $warningId = $this->id . '-warning'; - - $warning = (string) self::warningMessage($warningId); - } - return (string) Element::div( Element::label($this->label)->props( 'for ' . $this->id, diff --git a/src/Forms/Password.php b/src/Forms/Password.php index be3cf23..ad7e036 100644 --- a/src/Forms/Password.php +++ b/src/Forms/Password.php @@ -15,17 +15,17 @@ class Password implements Stringable private string $id; /** - * @var string[] + * @var list */ private array $wrapperProperties = []; /** - * @var string[] + * @var list */ private array $labelProperties = []; /** - * @var string[] + * @var list */ private array $inputProperties = []; @@ -49,7 +49,7 @@ final private function __construct( private readonly string|Stringable $name, private readonly string|PropertyInterface $warningMessage = '' ) { - $this->id = $name; + $this->id = (string) $name; } public function id(string $id): self @@ -60,25 +60,25 @@ public function id(string $id): self public function wrapperProps(string ...$properties): self { - $this->wrapperProperties = $properties; + $this->wrapperProperties = array_values($properties); return $this; } public function labelProps(string ...$properties): self { - $this->labelProperties = $properties; + $this->labelProperties = array_values($properties); return $this; } public function inputProps(string ...$properties): self { - $this->inputProperties = $properties; + $this->inputProperties = array_values($properties); return $this; } public function content(string|Stringable ...$content): self { - $this->content = $content; + $this->content = array_values($content); return $this; } diff --git a/src/Forms/TextArea.php b/src/Forms/TextArea.php index 493415f..29077f6 100644 --- a/src/Forms/TextArea.php +++ b/src/Forms/TextArea.php @@ -13,22 +13,22 @@ class TextArea implements Stringable private string $id; /** - * @var string[] + * @var list */ private array $wrapperProperties = []; /** - * @var string[] + * @var list */ private array $labelProperties = []; /** - * @var string[] + * @var list */ private array $inputProperties = []; /** - * @var array + * @var list */ private array $content = []; @@ -58,25 +58,25 @@ public function id(string $id): self public function wrapperProps(string ...$properties): self { - $this->wrapperProperties = $properties; + $this->wrapperProperties = array_values($properties); return $this; } public function labelProps(string ...$properties): self { - $this->labelProperties = $properties; + $this->labelProperties = array_values($properties); return $this; } public function inputProps(string ...$properties): self { - $this->inputProperties = $properties; + $this->inputProperties = array_values($properties); return $this; } public function content(string|Stringable ...$content): self { - $this->content = $content; + $this->content = array_values($content); return $this; } diff --git a/src/Forms/TextInput.php b/src/Forms/TextInput.php index 7366275..73863d9 100644 --- a/src/Forms/TextInput.php +++ b/src/Forms/TextInput.php @@ -13,17 +13,17 @@ class TextInput implements Stringable private string $id; /** - * @var string[] + * @var list */ private array $wrapperProperties = []; /** - * @var string[] + * @var list */ private array $labelProperties = []; /** - * @var string[] + * @var list */ private array $inputProperties = []; @@ -58,25 +58,25 @@ public function id(string $id): self public function wrapperProps(string ...$properties): self { - $this->wrapperProperties = $properties; + $this->wrapperProperties = array_values($properties); return $this; } public function labelProps(string ...$properties): self { - $this->labelProperties = $properties; + $this->labelProperties = array_values($properties); return $this; } public function inputProps(string ...$properties): self { - $this->inputProperties = $properties; + $this->inputProperties = array_values($properties); return $this; } public function content(string|Stringable ...$content): self { - $this->content = $content; + $this->content = array_values($content); return $this; }