Last active
September 13, 2021 08:54
-
-
Save RianFuro/a9bfb8060ea86385350f8c5b7ce26c0b to your computer and use it in GitHub Desktop.
Extend the `<x-slot>` and `@slot` directives for laravel's blade engine with scoping capabilities
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| class BladeCompiler extends \Illuminate\View\Compilers\BladeCompiler | |
| { | |
| static array $slotStack = []; | |
| /** | |
| * Compile the component tags. | |
| * | |
| * @param string $value | |
| * @return string | |
| */ | |
| protected function compileComponentTags($value) | |
| { | |
| if (! $this->compilesComponentTags) { | |
| return $value; | |
| } | |
| return (new ComponentTagCompiler( | |
| $this->classComponentAliases, $this->classComponentNamespaces, $this | |
| ))->compile($value); | |
| } | |
| protected function compileSlot($expression) | |
| { | |
| [$slot, $data] = strpos($expression, ',') !== false | |
| ? array_map('trim', explode(',', substr($expression, 1, -1))) | |
| : [trim($expression, '()'), '']; | |
| $isScoped = preg_match('/\((?<args>.+)\)( use (?<uses>\(.+\)))?/', $data, $matches); | |
| static::$slotStack[] = compact('isScoped'); | |
| if ($isScoped) { | |
| $uses = isset($matches['uses']) | |
| ? array_map('trim', explode(',', $matches['uses'])) | |
| : []; | |
| array_push($uses, '$__env'); | |
| $uses = implode(', ', $uses); | |
| return implode('\n', [ | |
| "<?php \$__env->slot({$slot}, function ({$matches['args']}) use ({$uses}) { ?>" | |
| ]); | |
| } else return "<?php \$__env->slot{$expression}; ?>"; | |
| } | |
| /** | |
| * Compile the end-slot statements into valid PHP. | |
| * | |
| * @return string | |
| */ | |
| protected function compileEndSlot() | |
| { | |
| $slotMeta = array_pop(static::$slotStack); | |
| return $slotMeta['isScoped'] | |
| ? '<?php }); ?>' | |
| : '<?php $__env->endSlot(); ?>'; | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| class ComponentTagCompiler extends \Illuminate\View\Compilers\ComponentTagCompiler | |
| { | |
| public function compileSlots(string $value) | |
| { | |
| $value = preg_replace_callback('/<\s*x[\-\:]slot\s+(:?)name=(?<name>(\"[^\"]+\"|\\\'[^\\\']+\\\'|[^\s>]+))(\s+bindings=(?<bindings>(\"[^\"]+\"|\\\'[^\\\']+\\\'|[^\s>]+)))?\s*>/', function ($matches) { | |
| $isScoped = array_key_exists('bindings', $matches); | |
| $name = $this->stripQuotes($matches['name']); | |
| if ($matches[1] !== ':') { | |
| $name = "'{$name}'"; | |
| } | |
| if ($isScoped) { | |
| $bindings = trim($matches['bindings'], '"'); | |
| return " @slot({$name}, ({$bindings}))"; | |
| } else return " @slot({$name}) "; | |
| }, $value); | |
| return preg_replace('/<\/\s*x[\-\:]slot[^>]*>/', ' @endslot', $value); | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| use Illuminate\View\DynamicComponent; | |
| use Illuminate\Support\ServiceProvider; | |
| class SomeServiceProvider extends ServiceProvider | |
| { | |
| public function register() | |
| { | |
| $this->app->extend(\Illuminate\View\Compilers\BladeCompiler::class, function ($_, $app) { | |
| return tap(new BladeCompiler($app['files'], $app['config']['view.compiled']), function ($blade) { | |
| $blade->component('dynamic-component', DynamicComponent::class); | |
| }); | |
| }); | |
| } | |
| } |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Usage:
{{-- some-view.blade.php --}} <x-component> <x-slot name="slotname" bindings="$var1, $var2"> <b>{{ $var1 }}, {{ $var2 }}!</b> </x-slot> </x-component>{{-- component.blade.php --}} @isset($slotname) {{ $slotname('Hello', 'world') }} @endissetNotes:
<x-slot>is super simple and cannot deal with reordering the arguments, so<x-slot bindings="" name="">will not work!<x-slot>the old@slotsyntax should also work like so: