Subversion-Projekte lars-tiefland.laravel_shop

Revision

Revision 148 | Details | Vergleich mit vorheriger | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
148 lars 1
<?php
2
 
3
declare(strict_types=1);
4
 
5
namespace Termwind\Html;
6
 
7
use Termwind\Components\Element;
8
use Termwind\Termwind;
9
use Termwind\ValueObjects\Styles;
10
 
11
/**
12
 * @internal
13
 */
14
final class InheritStyles
15
{
16
    /**
17
     * Applies styles from parent element to child elements.
18
     *
19
     * @param  array<int, Element|string>  $elements
20
     * @return array<int, Element|string>
21
     */
22
    public function __invoke(array $elements, Styles $styles): array
23
    {
24
        $elements = array_values($elements);
25
 
26
        foreach ($elements as &$element) {
27
            if (is_string($element)) {
28
                $element = Termwind::raw($element);
29
            }
30
 
31
            $element->inheritFromStyles($styles);
32
        }
33
 
34
        /** @var Element[] $elements */
35
        if (($styles->getProperties()['styles']['display'] ?? 'inline') === 'flex') {
36
            $elements = $this->applyFlex($elements);
37
        }
38
 
39
        return match ($styles->getProperties()['styles']['justifyContent'] ?? false) {
40
            'between' => $this->applyJustifyBetween($elements),
41
            'evenly' => $this->applyJustifyEvenly($elements),
42
            'around' => $this->applyJustifyAround($elements),
43
            'center' => $this->applyJustifyCenter($elements),
44
            default => $elements,
45
        };
46
    }
47
 
48
    /**
49
     * Applies flex-1 to child elements with the class.
50
     *
51
     * @param  array<int, Element>  $elements
52
     * @return array<int, Element>
53
     */
54
    private function applyFlex(array $elements): array
55
    {
56
        [$totalWidth, $parentWidth] = $this->getWidthFromElements($elements);
57
 
58
        $width = max(0, array_reduce($elements, function ($carry, $element) {
59
            return $carry += $element->hasStyle('flex-1') ? $element->getInnerWidth() : 0;
60
        }, $parentWidth - $totalWidth));
61
 
62
        $flexed = array_values(array_filter(
63
            $elements, fn ($element) => $element->hasStyle('flex-1')
64
        ));
65
 
66
        foreach ($flexed as $index => &$element) {
67
            if ($width === 0 && ! ($element->getProperties()['styles']['contentRepeat'] ?? false)) {
68
                continue;
69
            }
70
 
71
            $float = $width / count($flexed);
72
            $elementWidth = floor($float);
73
 
74
            if ($index === count($flexed) - 1) {
75
                $elementWidth += ($float - floor($float)) * count($flexed);
76
            }
77
 
78
            $element->addStyle("w-{$elementWidth}");
79
        }
80
 
81
        return $elements;
82
    }
83
 
84
    /**
85
     * Applies the space between the elements.
86
     *
87
     * @param  array<int, Element>  $elements
88
     * @return array<int, Element|string>
89
     */
90
    private function applyJustifyBetween(array $elements): array
91
    {
621 lars 92
        if (count($elements) <= 1) {
93
            return $elements;
94
        }
95
 
148 lars 96
        [$totalWidth, $parentWidth] = $this->getWidthFromElements($elements);
97
        $space = ($parentWidth - $totalWidth) / (count($elements) - 1);
98
 
99
        if ($space < 1) {
100
            return $elements;
101
        }
102
 
103
        $arr = [];
104
 
105
        foreach ($elements as $index => &$element) {
106
            if ($index !== 0) {
107
                // Since there is no float pixel, on the last one it should round up...
108
                $length = $index === count($elements) - 1 ? ceil($space) : floor($space);
109
                $arr[] = str_repeat(' ', (int) $length);
110
            }
111
 
112
            $arr[] = $element;
113
        }
114
 
115
        return $arr;
116
    }
117
 
118
    /**
119
     * Applies the space between and around the elements.
120
     *
121
     * @param  array<int, Element>  $elements
122
     * @return array<int, Element|string>
123
     */
124
    private function applyJustifyEvenly(array $elements): array
125
    {
126
        [$totalWidth, $parentWidth] = $this->getWidthFromElements($elements);
127
        $space = ($parentWidth - $totalWidth) / (count($elements) + 1);
128
 
129
        if ($space < 1) {
130
            return $elements;
131
        }
132
 
133
        $arr = [];
134
        foreach ($elements as &$element) {
135
            $arr[] = str_repeat(' ', (int) floor($space));
136
            $arr[] = $element;
137
        }
138
 
139
        $decimals = ceil(($space - floor($space)) * (count($elements) + 1));
140
        $arr[] = str_repeat(' ', (int) (floor($space) + $decimals));
141
 
142
        return $arr;
143
    }
144
 
145
    /**
146
     * Applies the space around the elements.
147
     *
148
     * @param  array<int, Element>  $elements
149
     * @return array<int, Element|string>
150
     */
151
    private function applyJustifyAround(array $elements): array
152
    {
621 lars 153
        if (count($elements) === 0) {
154
            return $elements;
155
        }
156
 
148 lars 157
        [$totalWidth, $parentWidth] = $this->getWidthFromElements($elements);
158
        $space = ($parentWidth - $totalWidth) / count($elements);
159
 
160
        if ($space < 1) {
161
            return $elements;
162
        }
163
 
164
        $contentSize = $totalWidth;
165
        $arr = [];
166
 
167
        foreach ($elements as $index => &$element) {
168
            if ($index !== 0) {
169
                $arr[] = str_repeat(' ', (int) ceil($space));
170
                $contentSize += ceil($space);
171
            }
172
 
173
            $arr[] = $element;
174
        }
175
 
176
        return [
177
            str_repeat(' ', (int) floor(($parentWidth - $contentSize) / 2)),
178
            ...$arr,
179
            str_repeat(' ', (int) ceil(($parentWidth - $contentSize) / 2)),
180
        ];
181
    }
182
 
183
    /**
184
     * Applies the space on before first element and after last element.
185
     *
186
     * @param  array<int, Element>  $elements
187
     * @return array<int, Element|string>
188
     */
189
    private function applyJustifyCenter(array $elements): array
190
    {
191
        [$totalWidth, $parentWidth] = $this->getWidthFromElements($elements);
192
        $space = $parentWidth - $totalWidth;
193
 
194
        if ($space < 1) {
195
            return $elements;
196
        }
197
 
198
        return [
199
            str_repeat(' ', (int) floor($space / 2)),
200
            ...$elements,
201
            str_repeat(' ', (int) ceil($space / 2)),
202
        ];
203
    }
204
 
205
    /**
206
     * Gets the total width for the elements and their parent width.
207
     *
208
     * @param  array<int, Element>  $elements
209
     * @return int[]
210
     */
211
    private function getWidthFromElements(array $elements)
212
    {
213
        $totalWidth = (int) array_reduce($elements, fn ($carry, $element) => $carry += $element->getLength(), 0);
214
        $parentWidth = Styles::getParentWidth($elements[0]->getProperties()['parentStyles'] ?? []);
215
 
216
        return [$totalWidth, $parentWidth];
217
    }
218
}