diff --git a/src/Forms/EmailInput.php b/src/Forms/EmailInput.php new file mode 100644 index 0000000..058df56 --- /dev/null +++ b/src/Forms/EmailInput.php @@ -0,0 +1,103 @@ + $this->name . '-warning'; + } + // phpcs:enable + + /** + * @var string[] + */ + private array $labelProperties = []; + + /** + * @var string[] + */ + private array $inputProperties = []; + + public static function create( + string|Stringable $label, + string|Stringable $name, + string $value = '', + string|PropertyInterface $warningMessage = '' + ): self { + return new self($label, $name, $value, $warningMessage); + } + + final private function __construct( + private readonly string|Stringable $label, + private readonly string|Stringable $name, + private readonly string $value, + private readonly string|PropertyInterface $warningMessage = '' + ) { + } + + public function labelProps(string ...$properties): self + { + $this->labelProperties = $properties; + return $this; + } + + public function inputProps(string ...$properties): self + { + $this->inputProperties = $properties; + return $this; + } + + private function warningMessage(): string|PropertyInterface + { + if ($this->warningMessage === '') { + return ''; + } + + if (is_string($this->warningMessage)) { + return Element::p($this->warningMessage)->props( + 'id ' . $this->warningId + ); + } + + return $this->warningMessage->prop('id ' . $this->warningId); + } + + public function __toString(): string + { + $elements = []; + $elements[] = Element::label($this->label)->props( + 'for ' . $this->name, + ...$this->labelProperties + ); + + $input = Element::input()->omitEndTag()->props( + 'type email', + 'id ' . $this->name, + 'name ' . $this->name, + 'value ' . $this->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)); + } +} diff --git a/src/Forms/Password.php b/src/Forms/Password.php new file mode 100644 index 0000000..825493b --- /dev/null +++ b/src/Forms/Password.php @@ -0,0 +1,124 @@ + $this->name . '-warning'; + } + // phpcs:enable + + /** + * @var string[] + */ + private array $labelProperties = []; + + /** + * @var string[] + */ + private array $inputProperties = []; + + + private PasswordAutocomplete $autocomplete = PasswordAutocomplete::CurrentPassword; + + public static function create( + string|Stringable $label, + string|Stringable $name, + string|PropertyInterface $warningMessage = '' + ): self { + return new self($label, $name, $warningMessage); + } + + final private function __construct( + private readonly string|Stringable $label, + private readonly string|Stringable $name, + private readonly string|PropertyInterface $warningMessage = '' + ) { + } + + public function labelProps(string ...$properties): self + { + $this->labelProperties = $properties; + return $this; + } + + public function inputProps(string ...$properties): self + { + $this->inputProperties = $properties; + return $this; + } + + 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; + } + + private function warningMessage(): string|PropertyInterface + { + if ($this->warningMessage === '') { + return ''; + } + + if (is_string($this->warningMessage)) { + return Element::p($this->warningMessage)->props( + 'id ' . $this->warningId + ); + } + + return $this->warningMessage->prop('id ' . $this->warningId); + } + + public function __toString(): string + { + $elements = []; + $elements[] = Element::label($this->label)->props( + 'for ' . $this->name, + ...$this->labelProperties + ); + + $input = Element::input()->omitEndTag()->props( + 'type password', + 'id ' . $this->name, + '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)); + } +} diff --git a/src/Forms/PasswordAutocomplete.php b/src/Forms/PasswordAutocomplete.php new file mode 100644 index 0000000..ea99085 --- /dev/null +++ b/src/Forms/PasswordAutocomplete.php @@ -0,0 +1,19 @@ +options as $value => $content) { $value = (string) $value; $option = Element::option($content)->props('value ' . $value); @@ -180,7 +182,7 @@ private function selectDropdown(): Element $this->label )->props('for ' . $this->name, ...$this->labelProperties), $input, - self::warningMessage() + $warningMessage )->props(...$this->wrapperProperties); } @@ -189,7 +191,9 @@ private function selectOther(): Element $elements = []; $type = $this->type === SelectType::Checkbox ? 'checkbox' : 'radio'; - $hasWarningMessage = (self::warningMessage() !== ''); + $warningMessage = self::warningMessage(); + $hasWarningMessage = ($warningMessage !== ''); + foreach ($this->options as $value => $content) { $value = (string) $value; $id = $this->name . '-' . $value; @@ -215,7 +219,7 @@ private function selectOther(): Element } if ($hasWarningMessage) { - $elements[] = self::warningMessage(); + $elements[] = $warningMessage; } return Element::fieldset( diff --git a/src/Forms/TextInput.php b/src/Forms/TextInput.php new file mode 100644 index 0000000..d533770 --- /dev/null +++ b/src/Forms/TextInput.php @@ -0,0 +1,103 @@ + $this->name . '-warning'; + } + // phpcs:enable + + /** + * @var string[] + */ + private array $labelProperties = []; + + /** + * @var string[] + */ + private array $inputProperties = []; + + public static function create( + string|Stringable $label, + string|Stringable $name, + string $value = '', + string|PropertyInterface $warningMessage = '' + ): self { + return new self($label, $name, $value, $warningMessage); + } + + final private function __construct( + private readonly string|Stringable $label, + private readonly string|Stringable $name, + private readonly string $value, + private readonly string|PropertyInterface $warningMessage = '' + ) { + } + + public function labelProps(string ...$properties): self + { + $this->labelProperties = $properties; + return $this; + } + + public function inputProps(string ...$properties): self + { + $this->inputProperties = $properties; + return $this; + } + + private function warningMessage(): string|PropertyInterface + { + if ($this->warningMessage === '') { + return ''; + } + + if (is_string($this->warningMessage)) { + return Element::p($this->warningMessage)->props( + 'id ' . $this->warningId + ); + } + + return $this->warningMessage->prop('id ' . $this->warningId); + } + + public function __toString(): string + { + $elements = []; + $elements[] = Element::label($this->label)->props( + 'for ' . $this->name, + ...$this->labelProperties + ); + + $input = Element::input()->omitEndTag()->props( + 'type text', + 'id ' . $this->name, + 'name ' . $this->name, + 'value ' . $this->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)); + } +} diff --git a/tests/Forms/EmailInputTest.php b/tests/Forms/EmailInputTest.php new file mode 100644 index 0000000..d524ee5 --- /dev/null +++ b/tests/Forms/EmailInputTest.php @@ -0,0 +1,59 @@ +Email + html; + + $result = (string) EmailInput::create( + 'Email', + 'email', + 'support@8fold.pro' + ); + + parent::assertSame($expected, $result); + } + + #[Test] + public function can_set_warning_message(): void // phpcs:ignore + { + $expected = <<Email

Invalid value

+ html; + + $result = (string) EmailInput::create( + label: 'Email', + name: 'email', + warningMessage: 'Invalid value' + ); + + parent::assertSame($expected, $result); + } + + #[Test] + public function is_expected_base(): void // phpcs:ignore + { + $expected = <<Email + html; + + $result = (string) EmailInput::create( + 'Email', + 'email' + ); + + parent::assertSame($expected, $result); + } +} diff --git a/tests/Forms/PasswordTest.php b/tests/Forms/PasswordTest.php new file mode 100644 index 0000000..00d6bda --- /dev/null +++ b/tests/Forms/PasswordTest.php @@ -0,0 +1,80 @@ +Password

Invalid value

+ html; + + $result = (string) Password::create( + 'Password', + 'password', + 'Invalid value' + )->forNewPassword(); + + parent::assertSame($expected, $result); + } + + #[Test] + public function can_change_autocomplete(): void // phpcs:ignore + { + $expected = <<Password + html; + + $result = (string) Password::create( + 'Password', + 'password' + )->forNewPassword(); + + parent::assertSame($expected, $result); + + $expected = <<Password + html; + + $result = (string) Password::create( + 'Password', + 'password' + )->autocompleteOn(); + + parent::assertSame($expected, $result); + + $expected = <<Password + html; + + $result = (string) Password::create( + 'Password', + 'password' + )->autocompleteOff(); + + parent::assertSame($expected, $result); + } + + #[Test] + public function is_expected_base(): void // phpcs:ignore + { + $expected = <<Password + html; + + $result = (string) Password::create( + 'Password', + 'password' + ); + + parent::assertSame($expected, $result); + } +} diff --git a/tests/Forms/TextInputTest.php b/tests/Forms/TextInputTest.php new file mode 100644 index 0000000..e7b0579 --- /dev/null +++ b/tests/Forms/TextInputTest.php @@ -0,0 +1,59 @@ +Text + html; + + $result = (string) TextInput::create( + 'Text', + 'text', + 'Posted value' + ); + + parent::assertSame($expected, $result); + } + + #[Test] + public function can_set_warning_message(): void // phpcs:ignore + { + $expected = <<Text

Invalid value

+ html; + + $result = (string) TextInput::create( + label: 'Text', + name: 'text', + warningMessage: 'Invalid value' + ); + + parent::assertSame($expected, $result); + } + + #[Test] + public function is_expected_base(): void // phpcs:ignore + { + $expected = <<Text + html; + + $result = (string) TextInput::create( + 'Text', + 'text' + ); + + parent::assertSame($expected, $result); + } +}