Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[8.x] Consume Blade Directive #39080

Closed
wants to merge 2 commits into from
Closed

[8.x] Consume Blade Directive #39080

wants to merge 2 commits into from

Conversation

taylorotwell
Copy link
Member

From an idea by @calebporzio ...

When building complex Blade components, it's hard / impossible to access data passed into the parent from children in the parent's slot.

For a concrete example of the problem (using a x-menu component):

Usage

<x-menu color="blue">
    <x-menu.item>Foo</x-menu.item>
    <x-menu.item>Bar</x-menu.item>
    ...
</x-menu>

Notice we are passing in a "color" attribute to the parent component. Here's the parent component definition:

x-menu

@props(['color' => 'black'])

<ul ...>
    {{ $slot }}
</ul>

Now this component has access to $color, but it doesn't actually need it. We need to access $color from each menu-item component:

x-menu.item

<li class="bg-{{ $color }}-500">
    {{ $slot }}
</li>

Can now be done via @consume directive in the child... defaults are also supported if no consumable data with the given name can be found in the parent component stack...

x-menu.item

@consume(['color', 'foo' => 'default'])

<li class="bg-{{ $color }}-500">
    {{ $slot }}
</li>

@ricardogobbosouza
Copy link
Contributor

Amazing @taylorotwell
I needed it for my package https://github.com/datalogix/tall-kit

Is it possible to access recursively?

<x-menu color="blue">
    <x-menu.item>
        <x-link>Acceess here color</x-lik>
    </x-menu.item>
    ...
</x-menu>

@taylorotwell
Copy link
Member Author

taylorotwell commented Oct 4, 2021

@ricardogobbosouza

In your example, you are at a level where you already have access to the color - so just type it in?

<x-menu color="blue">
    <x-menu.item>
        <x-link>blue</x-lik>
    </x-menu.item>
    ...
</x-menu>

@Bazzly
Copy link

Bazzly commented Oct 4, 2021

This is a great one..👍

@GrahamCampbell GrahamCampbell changed the title Consume Blade Directive [8.x] Consume Blade Directive Oct 4, 2021
@inxilpro
Copy link
Contributor

inxilpro commented Oct 4, 2021

Is there a story for using this in class components? It reminds me a lot of #36512 and #36472 — it'd be nice to have a way for parents/children to share data easily that works for both anonymous and class-based components.

@taylorotwell
Copy link
Member Author

@inxilpro yeah I think this whole idea needs a bit more work IMO. Spatie took a context component approach but that approach won't work with slots (as noted in their documentation), which is one of the use cases we are trying to solve here. This approach works with slots but doesn't work great with plain components and child components.

@delta1186
Copy link

So in this specific example would this implementation not work with the tailwind tree shaking? I realize that this is just an example and an actual implementation could be used in the abstract and so this feature will still be awesome to have available. 🤙🏻

@ricardogobbosouza
Copy link
Contributor

@taylorotwell Another related issue would be slot props laravel/ideas#2116 (comment) has a package does this https://github.com/konradkalemba/blade-components-scoped-slots could be part of the core?

@inxilpro
Copy link
Contributor

inxilpro commented Oct 5, 2021

It seems like a child component could theoretically call getConsumableComponentData — maybe we could even add a $consumes property to View\Component to make it automatic:

abstract class Component
{
    protected $consumes = [];

    public function data()
    {
        $this->attributes = $this->attributes ?: $this->newAttributeBag();

        return array_merge(
            $this->extractPublicProperties(),
            $this->extractPublicMethods(), 
            $this->getConsumableComponentData()
        );
    }

    protected function getConsumableComponentData()
    {
        return View::getConsumableComponentData($this->consumes);
    }
}

@taylorotwell
Copy link
Member Author

@inxilpro if the child is an anonymous component that unfortunately doesn't solve the issue

@inxilpro
Copy link
Contributor

inxilpro commented Oct 5, 2021

But doesn't @consume address it for anonymous components?

@taylorotwell
Copy link
Member Author

No - it mainly only addresses it for slots sadly.

For example:

<div>
    <x-menu-item />
</div>

If this code example is the source of the parent component, that x-menu-item can't @consume data from the parent.

@inxilpro
Copy link
Contributor

inxilpro commented Oct 5, 2021

Ooh. I have an idea! How would you feel if this just worked implicitly? For example, in the code sample above $color would just be available to the child unless you explicitly passed a different color value to it? I have that working locally in a test branch…

@taylorotwell
Copy link
Member Author

@inxilpro I'm not entirely opposed to that if you want to PR it to this branch.

@inxilpro
Copy link
Contributor

inxilpro commented Oct 5, 2021

@taylorotwell take a look at #39092 when you have a chance.

@inxilpro
Copy link
Contributor

inxilpro commented Oct 5, 2021

Alright. I put together one more try with #39100.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants