-
-
Notifications
You must be signed in to change notification settings - Fork 356
[Twig] Allow nested attributes #1405
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
Conversation
I'm still thinking about how we could pass nested attributes down to nested components: Something like: {# Form #}
<form{{ attributes }}>
<twig:Input :_attributes="attributes.nested('input')" />
<!-- or -->
<twig:Input ...attributes.nested('input') />
</form> |
Oh that's a really nice feature ! 👏 Does it work with live components ? (please say no hahaha) |
I think it would actually, only the rendering of the attributes takes the "nested" syntax into account. |
Solved! <twig:Input {{ ...attributes.nested('input') }} /> |
Little question just to be curious, nothing about "right now" ;) Would this be a lot of work to handle (same thing but in "json" notation instead of "html") ?
|
35e65c7
to
57dc323
Compare
I think the current syntax looks cleaner (just standard html attributes). |
57dc323
to
4bda8ed
Compare
Regarding the CI failure, it's because I'm using the twig spread operator in a test. I either need to bump the min twig version or skip this test if not supported. Thoughts? |
Skip for now ? We will probably drop Twig < 3.something when Twig 4.0 is released right ? |
cdcb87f
to
84839d2
Compare
I've wondered about how to do this a bunch of times 😅. I had imagined it working via blocks someday: <twig:MyDialog class="foo">
<twig:block name="footer" class="baz">Footer</twig:block>
</twig:MyDialog> That's a bit inspired by Blade, because our blocks == Blade slots, and they have slot attributes - https://laravel.com/docs/10.x/blade#slot-attributes However, 3 issues I see are: A) What if I wanted to define a B) Do we want to require a block in order to render an element with "nested" attributes? C) The more obvious issue is: blocks are a core concept... so this may not even be possible unless we modify Twig itself. Though, I had imagined that we might cheat by doing a translation: <twig:MyDialog class="foo">
<twig:block name="footer" class="baz">Footer</twig:block>
</twig:MyDialog>
becomes (line breaks added for clarity)
{% component 'MyDialog' with { class: 'foo' } %}
{% block footer %}
{% do attributes.nested('footer', { class: 'baz' }) %}
Footer
{% endblock %}
{% endblock %} The usage would be: {# Modal.html.twig #}
<div{{ attributes }}>
{% block footer %}
<div{{ attributes.nested('footer') }}>
{% block footer %}Default Footer{% endblock %}
</div>
</div> Not sure this is better, tbh. But I wanted to throw out this alternate universe before we decide on a syntax. |
We could totally use a intermediary tag like "slot" |
Wasn't the issue with this: we won't have the benefits of blocks? I think this was the reason we ended up abandoning a new slot type.
The block attributes system is interesting but it wouldn't solve the initial reason for me creating this PR: passing nested attributes to subcomponents. What I like about this implementation is it doesn't require any new twig fanciness. |
Was'nt this before the HTML syntax ? I feel we have learned a lot about "hacking" things into Twig since, maybe there is more things "possible" than before ? Did you remember what specifically in the "benefits of blocks" was laking ? Or list some of those you count more on ? |
Possibly, I can't quite remember.
I just remember Ryan and I realizing how powerful the out of the box block system was and all the benefits we'd be missing by doing our own thing. |
Yup, the block system is massively powerful and we should keep using it. I'm leaning towards "let's merge this & we could always deprecate it later). But
<twig:Input {{ ...attributes.nested('input') }} /> That problem occurred to me also:
It could possibly work via: <twig:Form>
<twig:block name="widget" class="ui-form-widget" />
</twig:Form> It would require defining a self-closing {% component 'Form' %}
{% do attributes.nested('widget', { class: 'ui-form-widget' }) %}
{% endcomponent %} Inside
On the one hand, this feels much crazier than your solution. On the other hand, this is a hard problem because it's not solved in Twig. And that's what we're trying to do here - ideally with the best API possible. |
… (kbond) This PR was merged into the 2.x branch. Discussion ---------- [Twig] Make `ComponentAttributes` traversable/countable | Q | A | ------------- | --- | Bug fix? | no | New feature? | yes | Issues | n/a | License | MIT This will help with #1405 and #1414. Commits ------- 8040d9c feat(twig): make `ComponentAttributes` traversable/countable
Do you mean |
84839d2
to
534b9f5
Compare
:class="bar" may be invalid.... But on custom elements, class:="bar" is not ;) <!DOCTYPE html>
<html>
<head>
<title>Hello</title>
</head>
<body>
<twig-bar class:="foo"></twig-bar>
</body>
</html> This is perfectly valid HTML code ;) |
For me, it looks like PhpStorm marks attributes with
Edit: The official tailwindcss plugin allows adding custom class names (I can add "widget:class" to the "classAttributes" config and it works). There is an experimental regex option that I think we could make work for |
I think all this can be handled with IDE, syntax rules, Symfony plugin... and i personnaly prefer a syntax non final (different from the HTML produced) The only question should be: what is at risk if something not intended to is displayed in HTML. -- In a (not-so) distant future, i'm more and more convinced by using "custom web components" syntax instead of our current "grammar-free custom XML namespace") .... That would allow us reserved attribute, custom syntax rules, templates,... and would offer incredible possibilities in term of lazy load too .... while beeing entirely supported in HTML/Twig editors |
534b9f5
to
2b699a9
Compare
2b699a9
to
8ee104a
Compare
8ee104a
to
e5b3896
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I approve for you to merge :) But still nitpicking doc things we can send later
You can have attributes that aren't meant to be used on the *root* element | ||
but one of its *descendants*. This is useful for, say, a dialog component where | ||
you want to allow customizing the attributes of the dialog's content, title, | ||
and footer. Here's an example of this: | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can pass attributes from the outside directly to the descendants of a component. This approach is especially useful for components like dialogs, to configure the rendering of inner parts like content, title, and footer. Here's an example:
</div> | ||
</div> | ||
|
||
The nesting is recursive so you could potentially do something like this: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm on very small details but this is not really recursive and more a tree here (in the meaning a parent call child, but never call itself back)
This paragraph and your following example make me want to do two small TwigComponent demos
- one litterally recursive where you pass to the child a level max and something a bit dynamic (oh i think i have n idea, poke me if your'e around) and the recursion goes until the level is reached
- a form demo with a cool theme, just like you did.
WDYT ?
(and we need to start the TwigComponent demo)
@@ -19,8 +19,10 @@ | |||
* | |||
* @immutable | |||
*/ | |||
final class ComponentAttributes implements \IteratorAggregate, \Countable | |||
final class ComponentAttributes implements \Stringable, \IteratorAggregate, \Countable |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
<3
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Later on, that'be nice if we could add some more tests on this.. to ensure non-regressive later PR, and maybe one or two on "non-happy-path". I'd be glad to help if you want)
:)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM! Thanks @kbond!
Thanks! @smnandre, when time permits, mind making a followup PR with some of the doc changes/tests you'd like? |
Will do in April... but won't mind a bit of help on this :)) |
This PR adds a syntax for nested attributes: attributes that aren't meant to be used on the root element but one of its descendants.
Here's an example:
The nesting is recursive so you could potentially do something like this: