Subversion-Projekte lars-tiefland.laravel_shop

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\Actions;
6
 
7
use Termwind\Exceptions\StyleNotFound;
8
use Termwind\Repositories\Styles as StyleRepository;
9
use Termwind\Terminal;
10
use Termwind\ValueObjects\Styles;
11
 
12
/**
13
 * @internal
14
 */
15
final class StyleToMethod
16
{
17
    /**
18
     * Finds if there is any media query on the style class.
19
     */
20
    private const MEDIA_QUERIES_REGEX = "/^(sm|md|lg|xl|2xl)\:(.*)/";
21
 
22
    /**
23
     * Defines the Media Query Breakpoints.
24
     */
25
    public const MEDIA_QUERY_BREAKPOINTS = [
26
        'sm' => 64,
27
        'md' => 76,
28
        'lg' => 102,
29
        'xl' => 128,
30
        '2xl' => 153,
31
    ];
32
 
33
    /**
34
     * Creates a new action instance.
35
     */
36
    public function __construct(
37
        private Styles $styles,
38
        private string $style,
39
    ) {
40
        // ..
41
    }
42
 
43
    /**
44
     * Applies multiple styles to the given styles.
45
     */
46
    public static function multiple(Styles $styles, string $stylesString): Styles
47
    {
48
        $stylesString = self::sortStyles(array_merge(
49
            $styles->defaultStyles(),
50
            array_filter((array) preg_split('/(?![^\[]*\])\s/', $stylesString))
51
        ));
52
 
53
        foreach ($stylesString as $style) {
54
            $styles = (new self($styles, $style))->__invoke();
55
        }
56
 
57
        return $styles;
58
    }
59
 
60
    /**
61
     * Converts the given style to a method name.
62
     *
63
     * @return Styles
64
     */
65
    public function __invoke(string|int ...$arguments): Styles
66
    {
67
        if (StyleRepository::has($this->style)) {
68
            return StyleRepository::get($this->style)($this->styles, ...$arguments);
69
        }
70
 
71
        $method = $this->applyMediaQuery($this->style);
72
 
73
        if ($method === '') {
74
            return $this->styles;
75
        }
76
 
77
        $method = array_filter(
78
            (array) preg_split('/(?![^\[]*\])-/', $method),
79
            fn ($item) => $item !== false
80
        );
81
 
82
        $method = array_slice($method, 0, count($method) - count($arguments));
83
 
84
        $methodName = implode(' ', $method);
85
        $methodName = ucwords($methodName);
86
        $methodName = lcfirst($methodName);
87
        $methodName = str_replace(' ', '', $methodName);
88
 
89
        if ($methodName === '') {
90
            throw StyleNotFound::fromStyle($this->style);
91
        }
92
 
93
        if (! method_exists($this->styles, $methodName)) {
94
            $argument = array_pop($method);
95
 
96
            $arguments[] = is_numeric($argument) ? (int) $argument : (string) $argument;
97
 
98
            return $this->__invoke(...$arguments);
99
        }
100
 
101
        return $this->styles
102
            ->setStyle($this->style)
103
            ->$methodName(...array_reverse($arguments));
104
    }
105
 
106
    /**
107
     * Sorts all the styles based on the correct render order.
108
     *
109
     * @param  string[]  $styles
110
     * @return string[]
111
     */
112
    private static function sortStyles(array $styles): array
113
    {
114
        $keys = array_keys(self::MEDIA_QUERY_BREAKPOINTS);
115
 
116
        usort($styles, function ($a, $b) use ($keys) {
117
            $existsA = (bool) preg_match(self::MEDIA_QUERIES_REGEX, $a, $matchesA);
118
            $existsB = (bool) preg_match(self::MEDIA_QUERIES_REGEX, $b, $matchesB);
119
 
120
            if ($existsA && ! $existsB) {
121
                return 1;
122
            }
123
 
124
            if ($existsA && array_search($matchesA[1], $keys, true) > array_search($matchesB[1], $keys, true)) {
125
                return 1;
126
            }
127
 
128
            return -1;
129
        });
130
 
131
        return $styles;
132
    }
133
 
134
    /**
135
     * Applies the media query if exists.
136
     */
137
    private function applyMediaQuery(string $method): string
138
    {
139
        $matches = [];
140
        preg_match(self::MEDIA_QUERIES_REGEX, $method, $matches);
141
 
142
        if (count($matches) < 1) {
143
            return $method;
144
        }
145
 
146
        [, $size, $method] = $matches;
147
 
148
        if ((new Terminal)->width() >= self::MEDIA_QUERY_BREAKPOINTS[$size]) {
149
            return $method;
150
        }
151
 
152
        return '';
153
    }
154
}