Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 25
0.00% covered (danger)
0.00%
0 / 15
CRAP
0.00% covered (danger)
0.00%
0 / 1
Accordion
0.00% covered (danger)
0.00%
0 / 25
0.00% covered (danger)
0.00%
0 / 15
306
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
 getId
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getTitle
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getDescription
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getContent
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getSeparation
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 isOpen
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getAttributes
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 setId
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 setTitle
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 setDescription
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 setContent
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 setOpen
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 setSeparation
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 setAttributes
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
1<?php
2declare( strict_types = 1 );
3
4/**
5 * Accordion.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 `Accordion` 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\AccordionRenderer;
24use Wikimedia\Codex\Traits\ContentSetter;
25
26/**
27 * Accordion
28 *
29 * @category Component
30 * @package  Codex\Component
31 * @since    0.1.0
32 * @author   Doğu Abaris <abaris@null.net>
33 * @license  https://www.gnu.org/copyleft/gpl.html GPL-2.0-or-later
34 * @link     https://doc.wikimedia.org/codex/main/ Codex Documentation
35 */
36class Accordion extends Component {
37    use ContentSetter;
38
39    /**
40     * Allowed styles for the separation.
41     */
42    public const ALLOWED_SEPARATIONS = [
43        'none',
44        'minimal',
45        'divider',
46        'outline',
47    ];
48
49    private string $id = '';
50
51    public function __construct(
52        AccordionRenderer $renderer,
53        private string|HtmlSnippet $title,
54        private string|HtmlSnippet $description,
55        private string|HtmlSnippet $content,
56        private bool $open,
57        private string $separation,
58        private array $attributes
59    ) {
60        parent::__construct( $renderer );
61    }
62
63    /**
64     * Get the accordion's HTML ID attribute.
65     *
66     * This method returns the ID assigned to the accordion element.
67     * The ID is useful for targeting the accordion with JavaScript, CSS, or accessibility features.
68     *
69     * @since 0.1.0
70     * @return string The ID of the accordion element.
71     */
72    public function getId(): string {
73        return $this->id;
74    }
75
76    /**
77     * Get the accordion's title.
78     *
79     * This method returns the title displayed in the header of the accordion.
80     * The title is the main clickable element that users interact with to expand or collapse
81     * the accordion's content.
82     *
83     * @since 0.1.0
84     * @return string The title of the accordion.
85     */
86    public function getTitle(): string|HtmlSnippet {
87        return $this->title;
88    }
89
90    /**
91     * Get the accordion's description.
92     *
93     * This method returns the description text that appears below the title in the accordion's header.
94     * The description provides additional context or details about the accordion's content.
95     *
96     * @since 0.1.0
97     * @return string The description of the accordion.
98     */
99    public function getDescription(): string|HtmlSnippet {
100        return $this->description;
101    }
102
103    /**
104     * Get the accordion's content.
105     *
106     * This method returns the content displayed when the accordion is expanded.
107     * The content can include various HTML elements such as text, images, and more.
108     *
109     * @since 0.1.0
110     * @return string|HtmlSnippet The content of the accordion, as HTML
111     */
112    public function getContent(): string|HtmlSnippet {
113        return $this->content;
114    }
115
116    /**
117     * Get the style of the separations.
118     *
119     * This method returns the separation style of the accordion, which indicates its visual prominence
120     * (e.g., 'none', 'minimal', 'divider', 'outline').
121     *
122     * @since @next
123     * @return string The style of the separation.
124     */
125    public function getSeparation(): string {
126        return $this->separation;
127    }
128
129    /**
130     * Check if the accordion is open by default.
131     *
132     * This method indicates whether the accordion is set to be expanded by default when the page loads.
133     * If true, the accordion is displayed in an expanded state.
134     *
135     * @since 0.1.0
136     * @return bool True if the accordion is open by default, false otherwise.
137     */
138    public function isOpen(): bool {
139        return $this->open;
140    }
141
142    /**
143     * Retrieve additional HTML attributes for the <details> element.
144     *
145     * This method returns an array of additional HTML attributes that will be applied
146     * to the `<details>` element of the accordion. The attributes are properly escaped
147     * to ensure security and prevent XSS vulnerabilities.
148     *
149     * @since 0.1.0
150     * @return array The additional attributes as an array.
151     */
152    public function getAttributes(): array {
153        return $this->attributes;
154    }
155
156    /**
157     * Set the accordion's HTML ID attribute.
158     *
159     * @deprecated Use setAttributes() to set the ID
160     * @since 0.1.0
161     * @param string $id The ID for the accordion element.
162     * @return $this
163     */
164    public function setId( string $id ): self {
165        $this->id = $id;
166
167        return $this;
168    }
169
170    /**
171     * Set the title for the accordion header.
172     *
173     * This method specifies the title text that appears in the accordion's header section.
174     * The title serves as the main clickable element that users interact with to expand or collapse
175     * the accordion content. The title is rendered inside a `<span>` element with the class
176     * `cdx-accordion__header__title`, which is nested within an `<h3>` header inside the `<summary>` element.
177     *
178     * The title should be concise yet descriptive enough to give users a clear understanding
179     * of the content they will see when the accordion is expanded.
180     *
181     * @since 0.1.0
182     * @param string|HtmlSnippet $title The title text to be displayed in the accordion header.
183     * @return $this Returns the Accordion instance for method chaining.
184     */
185    public function setTitle( string|HtmlSnippet $title ): self {
186        $this->title = $title;
187
188        return $this;
189    }
190
191    /**
192     * Set the description for the accordion header.
193     *
194     * The description is an optional text that provides additional context or details about the accordion's content.
195     * This text is displayed beneath the title in the header section and is wrapped in a `<span>` element with
196     * the class `cdx-accordion__header__description`. This description is particularly useful when the title alone
197     * does not fully convey the nature of the accordion's content.
198     *
199     * This method is especially helpful for making the accordion more accessible and informative,
200     * allowing users to understand the content before deciding to expand it.
201     *
202     * @since 0.1.0
203     * @param string|HtmlSnippet $description The description text to be displayed in the accordion header.
204     * @return $this Returns the Accordion instance for method chaining.
205     */
206    public function setDescription( string|HtmlSnippet $description ): self {
207        $this->description = $description;
208
209        return $this;
210    }
211
212    /**
213     * Set the content of the accordion.
214     *
215     * @param string|HtmlSnippet $content Text or HTML to be displayed inside the accordion.
216     * @return $this Returns the Accordion instance for method chaining.
217     */
218    public function setContent( string|HtmlSnippet $content ): self {
219        $this->content = $content;
220
221        return $this;
222    }
223
224    /**
225     * Set whether the accordion should be open by default.
226     *
227     * By default, accordions are rendered in a collapsed state. However, setting this property to `true`
228     * will cause the accordion to be expanded when the page initially loads. This adds the `open` attribute
229     * to the `<details>` element, making the content visible without interaction.
230     *
231     * This feature is useful in scenarios where critical content needs to be immediately visible, without requiring
232     * any action to expand the accordion.
233     *
234     * @since 0.1.0
235     * @param bool $isOpen Indicates whether the accordion should be open by default.
236     * @return $this Returns the Accordion instance for method chaining.
237     */
238    public function setOpen( bool $isOpen ): self {
239        $this->open = $isOpen;
240
241        return $this;
242    }
243
244    /**
245     * Set the style for the separations.
246     *
247     * This method sets the visual prominence of the separations, which can be:
248     * - 'none': No visual separation between accordion items (Default).
249     * - 'minimal': A low-emphasis style where only the header/title is highlighted.
250     * - 'divider': A standard horizontal line between items.
251     * - 'outline': Each accordion item is contained within its own border/box.
252     *
253     * The separation style is applied as a CSS class (`cdx-accordion--separation-{separation}`)
254     * to the details element.
255     *
256     * @since @next
257     * @param string $separation The style for the separation.
258     * @return $this Returns the Accordion instance for method chaining.
259     */
260    public function setSeparation( string $separation ): self {
261        if ( !in_array( $separation, self::ALLOWED_SEPARATIONS, true ) ) {
262            throw new InvalidArgumentException( "Invalid separation: $separation" );
263        }
264        $this->separation = $separation;
265
266        return $this;
267    }
268
269    /**
270     * Set additional HTML attributes for the `<details>` element.
271     *
272     * This method allows custom attributes to be added to the `<details>` element, such as `id`, `class`, `data-*`,
273     * `role`, or any other valid HTML attributes. These attributes can be used to further customize the accordion
274     * behavior, integrate it with JavaScript, or enhance accessibility.
275     *
276     * The values of these attributes are automatically escaped to prevent XSS vulnerabilities.
277     *
278     * Example usage:
279     *
280     *     $accordion->setAttributes([
281     *         'id' => 'some-id',
282     *         'data-toggle' => 'collapse'
283     *     ]);
284     *
285     * @since 0.1.0
286     * @param array $attributes An associative array of HTML attributes.
287     * @return $this Returns the Accordion instance for method chaining.
288     */
289    public function setAttributes( array $attributes ): self {
290        foreach ( $attributes as $key => $value ) {
291            $this->attributes[$key] = $value;
292        }
293        return $this;
294    }
295}