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 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 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 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); | |
}); | |
}); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Usage:
Notes:
<x-slot>
is super simple and cannot deal with reordering the arguments, so<x-slot bindings="" name="">
will not work!<x-slot>
the old@slot
syntax should also work like so: