Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 46
0.00% covered (danger)
0.00%
0 / 27
CRAP
0.00% covered (danger)
0.00%
0 / 1
TextInput
0.00% covered (danger)
0.00%
0 / 46
0.00% covered (danger)
0.00%
0 / 27
992
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getType
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getName
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getValue
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getPlaceholder
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getInputId
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 hasStartIcon
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 hasEndIcon
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getStartIconClass
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getEndIconClass
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 isDisabled
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getStatus
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getInputAttributes
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getWrapperAttributes
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 setType
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 setName
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 setValue
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 setInputId
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 setHasStartIcon
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 setHasEndIcon
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 setDisabled
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 setStatus
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 setStartIconClass
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 setEndIconClass
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 setInputAttributes
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 setWrapperAttributes
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 setPlaceholder
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2declare( strict_types = 1 );
3
4/**
5 * TextInput.php
6 *
7 * This file is part of the Codex design system, the official design system for Wikimedia projects.
8 * It contains the definition and implementation of the `TextInput` class, responsible for managing
9 * the behavior and properties of the corresponding component.
10 *
11 * @category Component
12 * @package  Codex\Component
13 * @since    0.1.0
14 * @author   Doğu Abaris <abaris@null.net>
15 * @license  https://www.gnu.org/copyleft/gpl.html GPL-2.0-or-later
16 * @link     https://doc.wikimedia.org/codex/main/ Codex Documentation
17 */
18
19namespace Wikimedia\Codex\Component;
20
21use InvalidArgumentException;
22use Wikimedia\Codex\Contract\Component;
23use Wikimedia\Codex\Renderer\TextInputRenderer;
24
25/**
26 * TextInput
27 *
28 * @category Component
29 * @package  Codex\Component
30 * @since    0.1.0
31 * @author   Doğu Abaris <abaris@null.net>
32 * @license  https://www.gnu.org/copyleft/gpl.html GPL-2.0-or-later
33 * @link     https://doc.wikimedia.org/codex/main/ Codex Documentation
34 */
35class TextInput extends Component {
36
37    /**
38     * Supported input types for the text input.
39     */
40    public const TEXT_INPUT_TYPES = [
41        'text',
42        'search',
43        'number',
44        'email',
45        'month',
46        'password',
47        'tel',
48        'url',
49        'week',
50        'date',
51        'datetime-local',
52        'time',
53    ];
54
55    /**
56     * Allowed validation statuses for the TextInput.
57     */
58    public const ALLOWED_STATUS_TYPES = [
59        'default',
60        'error',
61        'warning',
62        'success',
63    ];
64
65    public function __construct(
66        TextInputRenderer $renderer,
67        private string $type,
68        private string $name,
69        private string $value,
70        private string $inputId,
71        private string $placeholder,
72        private bool $disabled,
73        private string $status,
74        private array $inputAttributes,
75        private array $wrapperAttributes,
76        private bool $hasStartIcon,
77        private bool $hasEndIcon,
78        private ?string $startIconClass,
79        private ?string $endIconClass
80    ) {
81        parent::__construct( $renderer );
82    }
83
84    /**
85     * Get the type of the input field.
86     *
87     * This method returns the type attribute of the input field, which determines the type of data
88     * the input field accepts (e.g., 'text', 'email', 'password').
89     *
90     * @since 0.1.0
91     * @return string The type of the input field.
92     */
93    public function getType(): string {
94        return $this->type;
95    }
96
97    /**
98     * Get the name attribute of the input field.
99     *
100     * This method returns the name attribute of the input field, which is used to identify the input
101     * form control when submitting the form data.
102     *
103     * @since 0.1.0
104     * @return string The name attribute of the input field.
105     */
106    public function getName(): string {
107        return $this->name;
108    }
109
110    /**
111     * Get the value of the input field.
112     *
113     * This method returns the current value of the input field.
114     *
115     * @since 0.1.0
116     * @return string The value of the input field.
117     */
118    public function getValue(): string {
119        return $this->value;
120    }
121
122    /**
123     * Get the placeholder text of the input field.
124     *
125     * This method returns the placeholder text, which is displayed when the input field is empty.
126     * It provides a hint to the user about what should be entered in the field.
127     *
128     * @since 0.1.0
129     * @return string The placeholder text of the input field.
130     */
131    public function getPlaceholder(): string {
132        return $this->placeholder;
133    }
134
135    /**
136     * Get the ID of the input field.
137     *
138     * This method returns the ID attribute of the input field, which is useful for linking
139     * the input field to a label or for other JavaScript interactions.
140     *
141     * @since 0.1.0
142     * @return string The ID of the input field.
143     */
144    public function getInputId(): string {
145        return $this->inputId;
146    }
147
148    /**
149     * Check if the input field has a start icon.
150     *
151     * This method returns a boolean value indicating whether the input field has an icon at the start.
152     *
153     * @since 0.1.0
154     * @return bool True if the input field has a start icon, false otherwise.
155     */
156    public function hasStartIcon(): bool {
157        return $this->hasStartIcon;
158    }
159
160    /**
161     * Check if the input field has an end icon.
162     *
163     * This method returns a boolean value indicating whether the input field has an icon at the end.
164     *
165     * @since 0.1.0
166     * @return bool True if the input field has an end icon, false otherwise.
167     */
168    public function hasEndIcon(): bool {
169        return $this->hasEndIcon;
170    }
171
172    /**
173     * Get the CSS class for the start icon.
174     *
175     * This method returns the CSS class that is applied to the start icon, which can be used to style
176     * the icon or apply a background image.
177     *
178     * @since 0.1.0
179     * @return ?string The CSS class for the start icon.
180     */
181    public function getStartIconClass(): ?string {
182        return $this->startIconClass;
183    }
184
185    /**
186     * Get the CSS class for the end icon.
187     *
188     * This method returns the CSS class that is applied to the end icon, which can be used to style
189     * the icon or apply a background image.
190     *
191     * @since 0.1.0
192     * @return ?string The CSS class for the end icon.
193     */
194    public function getEndIconClass(): ?string {
195        return $this->endIconClass;
196    }
197
198    /**
199     * Check if the input field is disabled.
200     *
201     * This method returns a boolean value indicating whether the input field is disabled, making it uneditable.
202     *
203     * @since 0.1.0
204     * @return bool True if the input field is disabled, false otherwise.
205     */
206    public function isDisabled(): bool {
207        return $this->disabled;
208    }
209
210    /**
211     * Get the validation status of the input.
212     *
213     * This method returns a string value indicating the current validation status, which is used to
214     * add a CSS class that can be used for special styles per status.
215     *
216     * @since 0.1.0
217     * @return string Validation status, e.g. 'default' or 'error'.
218     */
219    public function getStatus(): string {
220        return $this->status;
221    }
222
223    /**
224     * Get additional HTML attributes for the input element.
225     *
226     * This method returns an associative array of custom HTML attributes that are applied to the input element,
227     * such as `data-*`, `aria-*`, or any other valid attributes that enhance functionality or accessibility.
228     *
229     * @since 0.1.0
230     * @return array The associative array of HTML attributes for the input element.
231     */
232    public function getInputAttributes(): array {
233        return $this->inputAttributes;
234    }
235
236    /**
237     * Get additional HTML attributes for the outer wrapper element.
238     *
239     * This method returns an associative array of custom HTML attributes that are applied to the outer wrapper element,
240     * enhancing its behavior or styling.
241     *
242     * @since 0.1.0
243     * @return array The associative array of HTML attributes for the wrapper element.
244     */
245    public function getWrapperAttributes(): array {
246        return $this->wrapperAttributes;
247    }
248
249    /**
250     * Set the type of the input field.
251     *
252     * This method sets the type attribute of the input field, which determines
253     * the type of data the input field accepts, such as 'text', 'email', 'password', etc.
254     *
255     * Example usage:
256     *
257     *     $textInput->setType('email');
258     *
259     * @since 0.1.0
260     * @param string $type The type of the input field (e.g., 'text', 'email').
261     * @return $this Returns the TextInput instance for method chaining.
262     */
263    public function setType( string $type ): self {
264        if ( !in_array( $type, self::TEXT_INPUT_TYPES, true ) ) {
265            throw new InvalidArgumentException( "Invalid input type: $type" );
266        }
267        $this->type = $type;
268
269        return $this;
270    }
271
272    /**
273     * Set the name attribute for the input field.
274     *
275     * This method specifies the name attribute for the input field, which is used to identify
276     * the input form control when submitting the form data.
277     *
278     * Example usage:
279     *
280     *     $textInput->setName('email');
281     *
282     * @since 0.1.0
283     * @param string $name The name attribute for the input field.
284     * @return $this Returns the TextInput instance for method chaining.
285     */
286    public function setName( string $name ): self {
287        $this->name = $name;
288
289        return $this;
290    }
291
292    /**
293     * Set the value attribute for the input field.
294     *
295     * This method specifies the value attribute for the input field, which represents the
296     * current value of the input field.
297     *
298     * Example usage:
299     *
300     *     $textInput->setValue('example@example.com');
301     *
302     * @since 0.1.0
303     * @param string $value The value of the input field.
304     * @return $this Returns the TextInput instance for method chaining.
305     */
306    public function setValue( string $value ): self {
307        $this->value = $value;
308
309        return $this;
310    }
311
312    /**
313     * Set the ID for the input field.
314     *
315     * This method sets the ID attribute for the input field, which is useful for linking
316     * the input field to a label or for other JavaScript interactions.
317     *
318     * Example usage:
319     *
320     *     $textInput->setInputId('email-input');
321     *
322     * @since 0.1.0
323     * @param string $inputId The ID of the input field.
324     * @return $this Returns the TextInput instance for method chaining.
325     */
326    public function setInputId( string $inputId ): self {
327        $this->inputId = $inputId;
328
329        return $this;
330    }
331
332    /**
333     * Set whether the input has a start icon.
334     *
335     * This method specifies whether the input field should have an icon at the start.
336     * The icon can be used to visually indicate the type of input expected.
337     *
338     * Example usage:
339     *
340     *     $textInput->setHasStartIcon(true);
341     *
342     * @since 0.1.0
343     * @param bool $hasStartIcon Indicates whether the input field has a start icon.
344     * @return $this Returns the TextInput instance for method chaining.
345     */
346    public function setHasStartIcon( bool $hasStartIcon ): self {
347        $this->hasStartIcon = $hasStartIcon;
348
349        return $this;
350    }
351
352    /**
353     * Set whether the input has an end icon.
354     *
355     * This method specifies whether the input field should have an icon at the end.
356     * The icon can be used to visually indicate additional functionality or context.
357     *
358     * Example usage:
359     *
360     *     $textInput->setHasEndIcon(true);
361     *
362     * @since 0.1.0
363     * @param bool $hasEndIcon Indicates whether the input field has an end icon.
364     * @return $this Returns the TextInput instance for method chaining.
365     */
366    public function setHasEndIcon( bool $hasEndIcon ): self {
367        $this->hasEndIcon = $hasEndIcon;
368
369        return $this;
370    }
371
372    /**
373     * Set whether the input is disabled.
374     *
375     * This method disables the input field, making it uneditable and visually distinct.
376     * The disabled attribute is useful for read-only forms or when the input is temporarily inactive.
377     *
378     * Example usage:
379     *
380     *     $textInput->setDisabled(true);
381     *
382     * @since 0.1.0
383     * @param bool $disabled Indicates whether the input field should be disabled.
384     * @return $this Returns the TextInput instance for method chaining.
385     */
386    public function setDisabled( bool $disabled ): self {
387        $this->disabled = $disabled;
388
389        return $this;
390    }
391
392    /**
393     * Set the validation status for the input.
394     *
395     * Example usage:
396     *
397     *     $textInput->setStatus('error');
398     *
399     * @since 0.1.0
400     * @param string $status Current validation status.
401     * @return $this
402     */
403    public function setStatus( string $status ): self {
404        if ( !in_array( $status, self::ALLOWED_STATUS_TYPES, true ) ) {
405            throw new InvalidArgumentException( "Invalid status: $status" );
406        }
407        $this->status = $status;
408
409        return $this;
410    }
411
412    /**
413     * Set the CSS class for the start icon.
414     *
415     * This method specifies the CSS class that will be applied to the start icon.
416     * The class can be used to style the icon or apply a background image.
417     *
418     * Example usage:
419     *
420     *     $textInput->setStartIconClass('icon-class-name');
421     *
422     * @since 0.1.0
423     * @param string $startIconClass The CSS class for the start icon.
424     * @return $this Returns the TextInput instance for method chaining.
425     */
426    public function setStartIconClass( string $startIconClass ): self {
427        $this->startIconClass = $startIconClass;
428
429        return $this;
430    }
431
432    /**
433     * Set the CSS class for the end icon.
434     *
435     * This method specifies the CSS class that will be applied to the end icon.
436     * The class can be used to style the icon or apply a background image.
437     *
438     * Example usage:
439     *
440     *     $textInput->setEndIconClass('icon-class-name');
441     *
442     * @since 0.1.0
443     * @param string $endIconClass The CSS class for the end icon.
444     * @return $this Returns the TextInput instance for method chaining.
445     */
446    public function setEndIconClass( string $endIconClass ): self {
447        $this->endIconClass = $endIconClass;
448
449        return $this;
450    }
451
452    /**
453     * Set additional HTML attributes for the input element.
454     *
455     * This method allows custom HTML attributes to be added to the input element, such as `data-*`,
456     * `aria-*`, or any other valid attributes that enhance functionality or accessibility.
457     *
458     * Example usage:
459     *
460     *     $textInput->setInputAttributes(['data-test' => 'value']);
461     *
462     * @since 0.1.0
463     * @param array $inputAttributes An associative array of HTML attributes for the input element.
464     * @return $this Returns the TextInput instance for method chaining.
465     */
466    public function setInputAttributes( array $inputAttributes ): self {
467        foreach ( $inputAttributes as $key => $value ) {
468            $this->inputAttributes[$key] = $value;
469        }
470        return $this;
471    }
472
473    /**
474     * Set additional HTML attributes for the outer wrapper element.
475     *
476     * This method allows custom HTML attributes to be added to the outer wrapper element,
477     * enhancing its behavior or styling.
478     *
479     * Example usage:
480     *
481     *     $textInput->setWrapperAttributes(['id' => 'custom-wrapper']);
482     *
483     * @since 0.1.0
484     * @param array $wrapperAttributes An associative array of HTML attributes for the wrapper element.
485     * @return $this Returns the TextInput instance for method chaining.
486     */
487    public function setWrapperAttributes( array $wrapperAttributes ): self {
488        foreach ( $wrapperAttributes as $key => $value ) {
489            $this->wrapperAttributes[$key] = $value;
490        }
491        return $this;
492    }
493
494    /**
495     * Set the placeholder text for the input element.
496     *
497     * This method sets the placeholder text, which is displayed when the input field is empty.
498     * It provides a hint to the user about what should be entered in the field.
499     *
500     * Example usage:
501     *
502     *     $textInput->setPlaceholder('johndoe@example.com');
503     *
504     * @since 0.1.0
505     * @param string $placeholder The placeholder text for the input field.
506     * @return $this Returns the TextInput instance for method chaining.
507     */
508    public function setPlaceholder( string $placeholder ): self {
509        $this->placeholder = $placeholder;
510
511        return $this;
512    }
513}