Subversion-Projekte lars-tiefland.laravel_shop

Revision

Zur aktuellen Revision | Details | 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
    {
92
        [$totalWidth, $parentWidth] = $this->getWidthFromElements($elements);
93
        $space = ($parentWidth - $totalWidth) / (count($elements) - 1);
94
 
95
        if ($space < 1) {
96
            return $elements;
97
        }
98
 
99
        $arr = [];
100
 
101
        foreach ($elements as $index => &$element) {
102
            if ($index !== 0) {
103
                // Since there is no float pixel, on the last one it should round up...
104
                $length = $index === count($elements) - 1 ? ceil($space) : floor($space);
105
                $arr[] = str_repeat(' ', (int) $length);
106
            }
107
 
108
            $arr[] = $element;
109
        }
110
 
111
        return $arr;
112
    }
113
 
114
    /**
115
     * Applies the space between and around the elements.
116
     *
117
     * @param  array<int, Element>  $elements
118
     * @return array<int, Element|string>
119
     */
120
    private function applyJustifyEvenly(array $elements): array
121
    {
122
        [$totalWidth, $parentWidth] = $this->getWidthFromElements($elements);
123
        $space = ($parentWidth - $totalWidth) / (count($elements) + 1);
124
 
125
        if ($space < 1) {
126
            return $elements;
127
        }
128
 
129
        $arr = [];
130
        foreach ($elements as &$element) {
131
            $arr[] = str_repeat(' ', (int) floor($space));
132
            $arr[] = $element;
133
        }
134
 
135
        $decimals = ceil(($space - floor($space)) * (count($elements) + 1));
136
        $arr[] = str_repeat(' ', (int) (floor($space) + $decimals));
137
 
138
        return $arr;
139
    }
140
 
141
    /**
142
     * Applies the space around the elements.
143
     *
144
     * @param  array<int, Element>  $elements
145
     * @return array<int, Element|string>
146
     */
147
    private function applyJustifyAround(array $elements): array
148
    {
149
        [$totalWidth, $parentWidth] = $this->getWidthFromElements($elements);
150
        $space = ($parentWidth - $totalWidth) / count($elements);
151
 
152
        if ($space < 1) {
153
            return $elements;
154
        }
155
 
156
        $contentSize = $totalWidth;
157
        $arr = [];
158
 
159
        foreach ($elements as $index => &$element) {
160
            if ($index !== 0) {
161
                $arr[] = str_repeat(' ', (int) ceil($space));
162
                $contentSize += ceil($space);
163
            }
164
 
165
            $arr[] = $element;
166
        }
167
 
168
        return [
169
            str_repeat(' ', (int) floor(($parentWidth - $contentSize) / 2)),
170
            ...$arr,
171
            str_repeat(' ', (int) ceil(($parentWidth - $contentSize) / 2)),
172
        ];
173
    }
174
 
175
    /**
176
     * Applies the space on before first element and after last element.
177
     *
178
     * @param  array<int, Element>  $elements
179
     * @return array<int, Element|string>
180
     */
181
    private function applyJustifyCenter(array $elements): array
182
    {
183
        [$totalWidth, $parentWidth] = $this->getWidthFromElements($elements);
184
        $space = $parentWidth - $totalWidth;
185
 
186
        if ($space < 1) {
187
            return $elements;
188
        }
189
 
190
        return [
191
            str_repeat(' ', (int) floor($space / 2)),
192
            ...$elements,
193
            str_repeat(' ', (int) ceil($space / 2)),
194
        ];
195
    }
196
 
197
    /**
198
     * Gets the total width for the elements and their parent width.
199
     *
200
     * @param  array<int, Element>  $elements
201
     * @return int[]
202
     */
203
    private function getWidthFromElements(array $elements)
204
    {
205
        $totalWidth = (int) array_reduce($elements, fn ($carry, $element) => $carry += $element->getLength(), 0);
206
        $parentWidth = Styles::getParentWidth($elements[0]->getProperties()['parentStyles'] ?? []);
207
 
208
        return [$totalWidth, $parentWidth];
209
    }
210
}