1<?php
2
3
4namespace ComboStrap\TagAttribute;
5
6
7use ComboStrap\Bootstrap;
8use ComboStrap\ConditionalLength;
9use ComboStrap\Dimension;
10use ComboStrap\ExceptionBadArgument;
11use ComboStrap\GridTag;
12use ComboStrap\LogUtility;
13use ComboStrap\TagAttributes;
14
15class Align
16{
17    /**
18     * Class to center an element
19     */
20    public const CENTER_CLASS = "mx-auto";
21    const ALIGN_ATTRIBUTE = "align";
22
23    /**
24     * Children are also known as items in HTML/CSS
25     * ie list items, align-center-items, ...
26     */
27    const Y_CENTER_CHILDREN = "y-center-children";
28    const Y_TOP_CHILDREN = "y-top-children";
29    const X_CENTER_CHILDREN = "x-center-children";
30    const DEFAULT_AXIS = self::X_AXIS;
31    public const X_AXIS = "x";
32    public const Y_AXIS = "y";
33    const CANONICAL = self::ALIGN_ATTRIBUTE;
34
35    /**
36     * @param TagAttributes $attributes
37     */
38    public static function processAlignAttributes(TagAttributes &$attributes)
39    {
40        // The class shortcut
41        $align = self::ALIGN_ATTRIBUTE;
42        $alignAttributeValues = $attributes->getValueAndRemove($align);
43        if ($alignAttributeValues === null || $alignAttributeValues === "") {
44            return;
45        }
46
47        $flexAxis = null;
48        $blockAlign = false;
49        $alignValues = explode(" ", $alignAttributeValues);
50        foreach ($alignValues as $alignStringValue) {
51
52            try {
53                $conditionalAlignValue = ConditionalLength::createFromString($alignStringValue);
54            } catch (ExceptionBadArgument $e) {
55                LogUtility::error("The align value ($alignStringValue) is not a valid conditional value and was skipped", self::CANONICAL);
56                continue;
57            }
58            switch ($conditionalAlignValue->getLength()) {
59                case "center":
60                case "x-center":
61                    $blockAlign = true;
62                    $attributes->addClassName(self::CENTER_CLASS);
63                    /**
64                     * Don't set: `width:fit-content`
65                     * Setting is cool for a little block
66                     * but it will take the max width of all children
67                     * making the design not responsive if a table
68                     * with `width:max-content` is a children
69                     */
70                    break;
71                case "y-center":
72                    $flexAxis[self::Y_AXIS] = true;
73                    $breakpoint = $conditionalAlignValue->getBreakpointForBootstrapClass();
74                    $attributes->addClassName("align-self{$breakpoint}-center");
75                    break;
76                case "right":
77                case "end":
78                    $blockAlign = true;
79                    if (Bootstrap::getBootStrapMajorVersion() == Bootstrap::BootStrapFourMajorVersion) {
80                        $attributes->addStyleDeclarationIfNotSet("margin-left", "auto");
81                    } else {
82                        $attributes->addClassName("ms-auto");
83                    }
84                    $attributes->addStyleDeclarationIfNotSet(Dimension::WIDTH_KEY, "fit-content");
85                    break;
86                case "x-left-children":
87                case "left-children":
88                case "start-children":
89                case "x-start-children":
90                    $flexAxis[self::X_AXIS] = true;
91                    $breakpoint = $conditionalAlignValue->getBreakpointForBootstrapClass();
92                    switch (Bootstrap::getBootStrapMajorVersion()) {
93                        case Bootstrap::BootStrapFourMajorVersion:
94                            $attributes->addClassName("justify-content{$breakpoint}-left");
95                            break;
96                        default:
97                            $attributes->addClassName("justify-content{$breakpoint}-start");
98                    }
99                    break;
100                case "x-right-children":
101                case "right-children":
102                case "end-children":
103                case "x-end-children":
104                    $flexAxis[self::X_AXIS] = true;
105                    $breakpoint = $conditionalAlignValue->getBreakpointForBootstrapClass();
106                    switch (Bootstrap::getBootStrapMajorVersion()) {
107                        case Bootstrap::BootStrapFourMajorVersion:
108                            $attributes->addClassName("justify-content{$breakpoint}-right");
109                            break;
110                        default:
111                            $attributes->addClassName("justify-content{$breakpoint}-end");
112                    }
113                    break;
114                case "x-center-children":
115                case "center-children":
116                    $flexAxis[self::X_AXIS] = true;
117                    $breakpoint = $conditionalAlignValue->getBreakpointForBootstrapClass();
118                    $attributes->addClassName("justify-content{$breakpoint}-center");
119                    break;
120                case "x-between-children":
121                case "between-children":
122                    $flexAxis[self::X_AXIS] = true;
123                    $breakpoint = $conditionalAlignValue->getBreakpointForBootstrapClass();
124                    $attributes->addClassName("justify-content{$breakpoint}-between");
125                    break;
126                case self::Y_CENTER_CHILDREN:
127                    $flexAxis[self::Y_AXIS] = true;
128                    $breakpoint = $conditionalAlignValue->getBreakpointForBootstrapClass();
129                    $attributes->addClassName("align-items{$breakpoint}-center");
130                    break;
131                case self::Y_TOP_CHILDREN:
132                    $flexAxis[self::Y_AXIS] = true;
133                    $breakpoint = $conditionalAlignValue->getBreakpointForBootstrapClass();
134                    $attributes->addClassName("align-items{$breakpoint}-start");
135                    break;
136                case "text-center":
137                    $breakpoint = $conditionalAlignValue->getBreakpointForBootstrapClass();
138                    $attributes->addClassName("text{$breakpoint}-center");
139                    break;
140                case "text-left":
141                case "text-start":
142                    $breakpoint = $conditionalAlignValue->getBreakpointForBootstrapClass();
143                    switch (Bootstrap::getBootStrapMajorVersion()) {
144                        case Bootstrap::BootStrapFourMajorVersion:
145                            $attributes->addClassName("text{$breakpoint}-left");
146                            break;
147                        default:
148                            $attributes->addClassName("text{$breakpoint}-start");
149                    }
150                    break;
151                case "text-right":
152                case "text-end":
153                    $breakpoint = $conditionalAlignValue->getBreakpointForBootstrapClass();
154                    switch (Bootstrap::getBootStrapMajorVersion()) {
155                        case Bootstrap::BootStrapFourMajorVersion:
156                            $attributes->addClassName("text{$breakpoint}-right");
157                            break;
158                        default:
159                            $attributes->addClassName("text{$breakpoint}-end");
160                    }
161                    break;
162            }
163
164
165        }
166
167        /**
168         * For flex element
169         */
170        if ($flexAxis !== null) {
171            /**
172             * A bootstrap row is already a flex, no need to add it
173             */
174            if ($attributes->getLogicalTag() !== GridTag::TAG) {
175                $attributes->addClassName("d-flex");
176                if (!isset($flexAxis[self::Y_AXIS])) {
177                    /**
178                     * flex box change the line center of where the text is written
179                     * if a flex align attribute is used in a row, a itext or any other
180                     * component that is not a grid, we set it to center
181                     *
182                     * You can see this effect for instance on a badge, where the text will jump
183                     * to the top (the flex default), without centering the flex on y
184                     */
185                    $attributes->addClassName("align-items-center");
186                }
187            }
188        }
189
190        /**
191         * For inline element,
192         * center should be a block
193         * (svg is not a block by default for instance)
194         * !
195         * this should not be the case for flex block such as a row
196         * therefore the condition
197         * !
198         */
199        if ($blockAlign === true && in_array($attributes->getLogicalTag(), TagAttributes::INLINE_LOGICAL_ELEMENTS)) {
200            $attributes->addClassName("d-block");
201        }
202
203
204    }
205}
206