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