Skip to content

Commit 43b84a1

Browse files
authored
Fix same component in slot overriding parent attributes (#125)
* Fix same component attribute override * Refactor
1 parent 28565fb commit 43b84a1

File tree

5 files changed

+41
-26
lines changed

5 files changed

+41
-26
lines changed

src/Compiler/Compiler.php

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,6 @@ protected function compileComponentTag(ComponentNode $node, ComponentSource $sou
9797
{
9898
$hash = Utils::hash($source->path);
9999
$functionName = ($this->manager->isFolding() ? '__' : '_') . $hash;
100-
$slotsVariableName = '$slots' . $hash;
101100
[$attributesArrayString, $boundKeysArrayString] = $this->getAttributesAndBoundKeysArrayStrings($node->attributeString);
102101

103102
$output = '<' . '?php $__blaze->ensureRequired(\'' . $source->path . '\', $__blaze->compiledPath.\'/'. $hash . '.php\'); ?>' . "\n";
@@ -106,12 +105,18 @@ protected function compileComponentTag(ComponentNode $node, ComponentSource $sou
106105
$output .= '<' . '?php $__blaze->pushData(' . $attributesArrayString . '); ?>' . "\n";
107106
$output .= '<' . '?php ' . $functionName . '($__blaze, ' . $attributesArrayString . ', [], ' . $boundKeysArrayString . ', isset($this) ? $this : null); ?>' . "\n";
108107
} else {
108+
$slotsVariableName = '$__slots' . $hash;
109109
$attributesVariableName = '$__attrs' . $hash;
110+
$output .= '<' . '?php if (isset(' . $slotsVariableName . ')) $__slotsOriginal = ' . $slotsVariableName . '; ?>' . "\n";
111+
$output .= '<' . '?php if (isset(' . $attributesVariableName . ')) $__attrsOriginal = ' . $attributesVariableName . '; ?>' . "\n";
110112
$output .= '<' . '?php ' . $attributesVariableName . ' = ' . $attributesArrayString . '; ?>' . "\n";
113+
$output .= '<' . '?php ' . $slotsVariableName . ' = []; ?>' . "\n";
114+
$output .= $this->slotCompiler->compile($slotsVariableName, $node->children);
111115
$output .= '<' . '?php $__blaze->pushData(' . $attributesVariableName . '); ?>' . "\n";
112-
$output .= $this->slotCompiler->compile($slotsVariableName, $node->children) . "\n";
113116
$output .= '<' . '?php $__blaze->pushSlots(' . $slotsVariableName . '); ?>' . "\n";
114117
$output .= '<' . '?php ' . $functionName . '($__blaze, ' . $attributesVariableName . ', ' . $slotsVariableName . ', ' . $boundKeysArrayString . ', isset($this) ? $this : null); ?>' . "\n";
118+
$output .= '<' . '?php if (isset($__slotsOriginal)) {' . $slotsVariableName . ' = $__slotsOriginal; unset($__slotsOriginal); } ?>' . "\n";
119+
$output .= '<' . '?php if (isset($__attrsOriginal)) {' . $attributesVariableName . ' = $__attrsOriginal; unset($__attrsOriginal); } ?>' . "\n";
115120
}
116121

117122
$output .= '<' . '?php $__blaze->popData(); ?>';
@@ -125,23 +130,22 @@ protected function compileComponentTag(ComponentNode $node, ComponentSource $sou
125130
protected function compileDelegateComponentTag(ComponentNode $node): string
126131
{
127132
$componentName = "'flux::' . " . $node->attributes['component']->value;
128-
129-
$output = '<' . '?php $__resolved = $__blaze->resolve(' . $componentName . '); ?>' . "\n";
130-
131-
$slotsVariableName = '$slots' . hash('xxh128', $componentName);
132-
133133
$functionName = '(\'' . ($this->manager->isFolding() ? '__' : '_') . '\' . $__resolved)';
134-
134+
135+
$output = '<' . '?php $__resolved = $__blaze->resolve(' . $componentName . '); ?>' . "\n";
135136
$output .= '<' . '?php $__blaze->pushData($attributes->all()); ?>' . "\n";
136-
137137
$output .= '<' . '?php if ($__resolved !== false): ?>' . "\n";
138138

139139
if ($node->selfClosing) {
140140
$output .= '<' . '?php ' . $functionName . '($__blaze, $attributes->all(), $__blaze->mergedComponentSlots(), [], isset($this) ? $this : null); ?>' . "\n";
141141
} else {
142+
$slotsVariableName = '$__slots' . Utils::hash($componentName);
143+
$output .= '<' . '?php if (isset(' . $slotsVariableName . ')) $__slotsOriginal = ' . $slotsVariableName . '; ?>' . "\n";
144+
$output .= '<' . '?php ' . $slotsVariableName . ' = []; ?>' . "\n";
142145
$output .= $this->slotCompiler->compile($slotsVariableName, $node->children);
143146
$output .= '<' . '?php ' . $slotsVariableName . ' = array_merge($__blaze->mergedComponentSlots(), ' . $slotsVariableName . '); ?>' . "\n";
144147
$output .= '<' . '?php ' . $functionName . '($__blaze, $attributes->all(), ' . $slotsVariableName . ', [], isset($this) ? $this : null); ?>' . "\n";
148+
$output .= '<' . '?php if (isset($__slotsOriginal)) {' . $slotsVariableName . ' = $__slotsOriginal; unset($__slotsOriginal); } ?>' . "\n";
145149
}
146150

147151
$output .= '<' . '?php else: ?>' . "\n";

src/Compiler/SlotCompiler.php

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
use Closure;
66
use Illuminate\Support\Str;
7-
use Livewire\Blaze\Blaze;
87
use Livewire\Blaze\BlazeManager;
98
use Livewire\Blaze\Parser\Nodes\SlotNode;
109

@@ -26,27 +25,26 @@ public function __construct(
2625
*/
2726
public function compile(string $slotsVariableName, array $children): string
2827
{
29-
$output = [];
28+
$output = '';
3029

3130
// Compile implicit default slot from loose content (non-SlotNode children)
3231
if (! $this->hasExplicitDefaultSlot($children)) {
33-
$output[] = $this->compileSlot('slot', $this->renderLooseContent($children), '[]', $slotsVariableName);
32+
$output .= $this->compileSlot('slot', $this->renderLooseContent($children), '[]', $slotsVariableName) . "\n";
3433
}
3534

3635
// Compile each named slot
3736
foreach ($children as $child) {
3837
if ($child instanceof SlotNode) {
39-
$output[] = $this->compileSlot(
38+
$output .= $this->compileSlot(
4039
$this->resolveSlotName($child),
4140
$this->renderChildren($child->children),
4241
$this->compileSlotAttributes($child),
4342
$slotsVariableName,
44-
);
43+
) . "\n";
4544
}
4645
}
4746

48-
return '<' . '?php ' . $slotsVariableName . ' = []; ?>' . "\n"
49-
. implode("\n", $output);
47+
return $output;
5048
}
5149

5250
/**

tests/ComparisonTest.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,4 +90,13 @@
9090
<x-foldable.input :readonly="$readonly" />
9191
BLADE,
9292
['readonly' => false],
93+
));
94+
95+
test('same component in a slot doesnt affect parents attributes', fn () => compare(<<<'BLADE'
96+
<x-card>
97+
<x-card x-data>
98+
Hello World
99+
</x-card>
100+
</x-card>
101+
BLADE
93102
));

tests/Compiler/CompilerTest.php

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@
2121
]));
2222
});
2323

24-
test('compiles slots', function () {
24+
test('compiles components', function () {
2525
$input = <<<'BLADE'
26-
<x-card>
26+
<x-card class="mt-8">
2727
<x-slot:header class="p-2">
2828
Header
2929
</x-slot:header>
@@ -43,14 +43,18 @@
4343

4444
expect($compiled->render())->toEqualCollapsingWhitespace(join('', [
4545
'<?php $__blaze->ensureRequired(\''. $path .'\', $__blaze->compiledPath.\'/'. $hash .'.php\'); ?> ',
46-
'<?php $__attrs'. $hash .' = []; ?> ',
46+
'<?php if (isset($__slots'. $hash .')) $__slotsOriginal = $__slots'. $hash .'; ?> ',
47+
'<?php if (isset($__attrs'. $hash .')) $__attrsOriginal = $__attrs'. $hash .'; ?> ',
48+
'<?php $__attrs'. $hash .' = [\'class\' => \'mt-8\']; ?> ',
49+
'<?php $__slots'. $hash .' = []; ?> ',
50+
'<?php ob_start(); ?> Body <?php $__slots'. $hash .'[\'slot\'] = new \Illuminate\View\ComponentSlot(trim(ob_get_clean()), []); ?> ',
51+
'<?php ob_start(); ?> Header <?php $__slots'. $hash .'[\'header\'] = new \Illuminate\View\ComponentSlot(trim(ob_get_clean()), [\'class\' => \'p-2\']); ?> ',
52+
'<?php ob_start(); ?> Footer <?php $__slots'. $hash .'[\'footer\'] = new \Illuminate\View\ComponentSlot(trim(ob_get_clean()), [\'class\' => \'mt-4\']); ?> ',
4753
'<?php $__blaze->pushData($__attrs'. $hash .'); ?> ',
48-
'<?php $slots'. $hash .' = []; ?> ',
49-
'<?php ob_start(); ?> Body <?php $slots'. $hash .'[\'slot\'] = new \Illuminate\View\ComponentSlot(trim(ob_get_clean()), []); ?> ',
50-
'<?php ob_start(); ?> Header <?php $slots'. $hash .'[\'header\'] = new \Illuminate\View\ComponentSlot(trim(ob_get_clean()), [\'class\' => \'p-2\']); ?> ',
51-
'<?php ob_start(); ?> Footer <?php $slots'. $hash .'[\'footer\'] = new \Illuminate\View\ComponentSlot(trim(ob_get_clean()), [\'class\' => \'mt-4\']); ?> ',
52-
'<?php $__blaze->pushSlots($slots'. $hash .'); ?> ',
53-
'<?php _'. $hash .'($__blaze, $__attrs'. $hash .', $slots'. $hash .', [], isset($this) ? $this : null); ?> ',
54+
'<?php $__blaze->pushSlots($__slots'. $hash .'); ?> ',
55+
'<?php _'. $hash .'($__blaze, $__attrs'. $hash .', $__slots'. $hash .', [], isset($this) ? $this : null); ?> ',
56+
'<?php if (isset($__slotsOriginal)) {$__slots'. $hash .' = $__slotsOriginal; unset($__slotsOriginal); } ?> ',
57+
'<?php if (isset($__attrsOriginal)) {$__attrs'. $hash .' = $__attrsOriginal; unset($__attrsOriginal); } ?> ',
5458
'<?php $__blaze->popData(); ?>',
5559
]));
5660
});

tests/fixtures/views/components/card.blade.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22

33
@props([])
44

5-
<div>{{ $header ?? '' }} {{ $slot ?? '' }} {{ $footer ?? '' }}</div>
5+
<div {{ $attributes }}>{{ $header ?? '' }} {{ $slot ?? '' }} {{ $footer ?? '' }}</div>

0 commit comments

Comments
 (0)