nette / latte

☕ Latte: the safest & truly intuitive templates for PHP. Engine for those who want the most secure PHP sites.
https://latte.nette.org
Other
1.09k stars 107 forks source link

Support for n:embed #304

Open lubomirblazekcz opened 2 years ago

lubomirblazekcz commented 2 years ago

Currently it's possible to define component with n:define, like this

<button n:define="UiBtnPrimary, $type = 'solid'" data-type="{$type}" class="ui-btn bg-primary bg-opacity-10 font-normal">
    <span n:block="title"></span>
</button>

But it's not currently possible to embed it same way with n:embed, but latte plugin in phpstorm recognize this as valid latte attribute?

I think that n: macros are strong feature in latte, that no other php/js template engine has. With the strong adoption of TailwindCSS or AlpineJS, the n:define and n:embed would be strong feature for reusable UI components. You could define UI component with n:define and then reuse it in the code with n:embed. So there wouldn't be a lot of duplicated code with the same component. That's currently not possible to do in a good way with the other php/js template engines, and seems latte is one step away from this feature.

To embed that defined component, it's currently only possible to do with {embed}, like this

{embed UiBtnPrimary, $type = 'outline'}
    <span n:block="title">Hello World</span>
{/embed}

But this has it's limitations, let's say you want to extend the component with new classes, or attributes. You would have to define it as params in the n:define and add it as variables in the brackets {}, which could cause problems with tailwindcss detecting the classes, or other purgecss plugins.

Something like this would be much better and easier to use

<button n:embed="UiBtnPrimary" data-action="click->lib-dialog#show" data-action-url="path.json">
    <span n:block="title">Hello World</span>
</button>

Which would output to

<button data-type="outline" class="ui-btn bg-primary bg-opacity-10" data-action="click->lib-dialog#show" data-action-url="path.json">
    <span>Hello World</span>
</button>

Even better would be if define had something like js has <slot></slot>, so you wouldn't need to write block in embed everytime.

<button n:define="UiBtnPrimary, $type = 'solid'" data-type="{$type}" class="ui-btn bg-primary bg-opacity-10 font-normal">
    {slot}{/slot}
</button>

<button n:embed="UiBtnPrimary" data-action="click->lib-dialog#show" data-action-url="path.json">
    Hello World
</button>

For a big projects that reuse a lot of UI components this would be a massive improvement. In @newlogic-digital we noticed this ourselfs. We have a lot of UI components and templates in our projects, and if something like n:embed was possible it would result into reducing a lot of duplicate code. We try to use embed and include when possible, but it's not always ideal.

We would love to support nette and latte directly! I've sended a few emails and contacted you on twitter with no response 😞

dg commented 2 years ago

This could probably be done, with the caveat that attributes can only be added and the tag name cannot be changed. So this wouldn't work properly:

<button n:embed="UiBtnPrimary" data-type="different type">
    ...
</button>
<div n:embed="UiBtnPrimary">
    ...
</div>

ad {slot}: a related thought https://forum.nette.org/cs/35161-napad-embed-s-anonymnim-blokem

antiknown commented 8 months ago

Has there been any movement on this? Is there an alternate solution? I was thinking of custom HTML tags, similar to Web Components in the browser.

template:

<button class="py-2 px-4 bg-blue-500 text-white font-semibold">
    <span><slot></slot></span>
</button>

usage:

<x-button class="button-modifier">
    Hello World
</x-button>

output:

<button class="py-2 px-4 bg-blue-500 text-white font-semibold button-modifier">
    <span>Hello World</span>
</button>