55namespace Tempest \View \Elements ;
66
77use Tempest \Core \Environment ;
8+ use Tempest \Support \Arr \ImmutableArray ;
89use Tempest \Support \Str \ImmutableString ;
910use Tempest \Support \Str \MutableString ;
1011use Tempest \View \Element ;
@@ -41,58 +42,30 @@ public function getViewComponent(): ViewComponent
4142 return $ this ->viewComponent ;
4243 }
4344
44- /** @return Element[] */
45- public function getSlots (): array
45+ /** @return ImmutableArray<array-key, Slot> */
46+ public function getSlots (): ImmutableArray
4647 {
47- $ slots = [] ;
48+ $ slots = arr () ;
4849
49- foreach ($ this ->getChildren () as $ child ) {
50- if (! ($ child instanceof SlotElement)) {
51- continue ;
52- }
53-
54- $ slots [] = $ child ;
55- }
50+ $ default = [];
5651
57- return $ slots ;
58- }
59-
60- public function getSlot (string $ name = 'slot ' ): ?Element
61- {
6252 foreach ($ this ->getChildren () as $ child ) {
63- if (! ($ child instanceof SlotElement)) {
64- continue ;
65- }
53+ if ($ child instanceof SlotElement) {
54+ $ slot = Slot::fromElement ($ child );
6655
67- if ($ child ->matches ($ name )) {
68- return $ child ;
56+ $ slots [$ slot ->name ] = $ slot ;
57+ } else {
58+ $ default [] = $ child ;
6959 }
7060 }
7161
72- if ($ name === 'slot ' ) {
73- $ elements = [];
74-
75- foreach ($ this ->getChildren () as $ child ) {
76- if ($ child instanceof SlotElement) {
77- continue ;
78- }
79-
80- $ elements [] = $ child ;
81- }
82-
83- return new CollectionElement ($ elements );
84- }
62+ $ slots [Slot::DEFAULT ] = Slot::fromElement (new CollectionElement ($ default ));
8563
86- return null ;
64+ return $ slots ;
8765 }
8866
8967 public function compile (): string
9068 {
91- /** @var Slot[] $slots */
92- $ slots = arr ($ this ->getSlots ())
93- ->mapWithKeys (fn (SlotElement $ element ) => yield $ element ->name => Slot::fromElement ($ element ))
94- ->toArray ();
95-
9669 $ compiled = str ($ this ->viewComponent ->compile ($ this ));
9770
9871 $ compiled = $ compiled
@@ -135,6 +108,9 @@ public function compile(): string
135108 },
136109 );
137110
111+ // Add scoped variables
112+ $ slots = $ this ->getSlots ()->toArray ();
113+
138114 $ compiled = $ compiled
139115 ->prepend (
140116 // Add attributes to the current scope
@@ -155,38 +131,39 @@ public function compile(): string
155131 '<?php unset($attributes); ?> ' ,
156132 '<?php $attributes = $_previousAttributes ?? null; ?> ' ,
157133 '<?php unset($_previousAttributes); ?> ' ,
158- )
159- // Compile slots
160- ->replaceRegex (
161- regex: '/<x-slot\s*(name="(?<name>[\w-]+)")?((\s*\/>)|>(?<default>(.|\n)*?)<\/x-slot>)/ ' ,
162- replace: function ($ matches ) {
163- $ name = $ matches ['name ' ] ?: 'slot ' ;
134+ );
164135
165- $ slot = $ this ->getSlot ($ name );
136+ // Compile slots
137+ $ compiled = $ compiled ->replaceRegex (
138+ regex: '/<x-slot\s*(name="(?<name>[\w-]+)")?((\s*\/>)|>(?<default>(.|\n)*?)<\/x-slot>)/ ' ,
139+ replace: function ($ matches ) use ($ slots ) {
140+ $ name = $ matches ['name ' ] ?: Slot::DEFAULT ;
166141
167- $ default = $ matches [ ' default ' ] ?? null ;
142+ $ slot = $ slots [ $ name ] ?? null ;
168143
169- if ($ slot === null ) {
170- if ($ default ) {
171- // There's no slot, but there's a default value in the view component
172- return $ default ;
173- }
144+ $ default = $ matches ['default ' ] ?? null ;
174145
175- // A slot doesn't have any content, so we'll comment it out.
176- // This is to prevent DOM parsing errors (slots in <head> tags is one example, see #937)
177- return $ this ->environment ->isProduction () ? '' : ('<!-- ' . $ matches [0 ] . '--> ' );
146+ if ($ slot === null ) {
147+ if ($ default ) {
148+ // There's no slot, but there's a default value in the view component
149+ return $ default ;
178150 }
179151
180- $ compiled = $ slot ->compile ();
152+ // A slot doesn't have any content, so we'll comment it out.
153+ // This is to prevent DOM parsing errors (slots in <head> tags is one example, see #937)
154+ return $ this ->environment ->isProduction () ? '' : ('<!-- ' . $ matches [0 ] . '--> ' );
155+ }
181156
182- // There's no default slot content, but there's a default value in the view component
183- if (trim ($ compiled ) === '' ) {
184- return $ default ;
185- }
157+ $ compiled = $ slot ->content ;
186158
187- return $ compiled ;
188- },
189- );
159+ // There's no default slot content, but there's a default value in the view component
160+ if (trim ($ compiled ) === '' ) {
161+ return $ default ;
162+ }
163+
164+ return $ compiled ;
165+ },
166+ );
190167
191168 return $ this ->compiler ->compile ($ compiled ->toString ());
192169 }
0 commit comments