You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This PR was merged into the 2.x branch.
Discussion
----------
[WIP][TwigComponent] add component attribute system/helper
| Q | A
| ------------- | ---
| Bug fix? | no
| New feature? | yes
| Tickets | n/a
| License | MIT
A common pattern with other component library's (ie blade components/vue) is to pass html attributes to your component that are set on the component's root node. This proposal adds a way to do this with twig components. Enable on your component by adding the `HasAttributesTrait`. Attributes are any data passed to `component()` that cannot be mounted on the component itself. This extra data is added to a `ComponentAttributes` object that lives as a public property on your component (available as `attributes` in your component's template).
This should all work out-of-the box with live components.
Todo:
- [x] Tests
- [x] Documentation
- [x] #240
- [x] #241
- [x] Merge `init_live_component()` into attributes when available
- [x] Document `PreRender` event.
- [x] Adjust `ComponentAttributes` api (defaults instead of merge)
- [ ] `attributes` always available in normal twig component templates (not sure about this - it would effectively make attributes _native_ but it a lame way)
- [x] replace `init_live_component()` with `attributes` in docs
- [x] Finalize docs (versionadded tags)
## Usage
To use, add the `HasAttributesTrait` to your component:
```php
#[AsTwigComponent('my_component')]
class MyComponent
{
use HasAttributesTrait;
}
```
Then, in your component's template:
```twig
{# templates/components/my_component.html.twig #}
<div{{ attributes }}>
My Component!
</div>
```
When rendering the component, you can pass an array of html attributes to add:
```twig
{{ component('my_component', { class: 'foo', style: 'color:red' }) }}
{# renders as: #}
<div class="foo" style="color:red">
My Component!
</div>
```
### Defaults & Merging
In your component template, you can set defaults that are merged with
passed attributes. The passed attributes override the default with
the exception of *class*. For class, the defaults are prepended:
```twig
{# templates/components/my_component.html.twig #}
<button{{ attributes.defaults({ class: 'bar', type: 'button' }) }}>
My Component!
</button>
{# render component #}
{{ component('my_component', { style: 'color:red' }) }}
{{ component('my_component', { class: 'foo', type: 'submit' }) }}
{# renders as: #}
<div class="bar" style="color:red">
My Component!
</div>
<div class="bar foo" type="submit">
My Component!
</div>
```
### Only
```twig
{# templates/components/my_component.html.twig #}
<div{{ attributes.only('class')) }}>
My Component!
</div>
{# render component #}
{{ component('my_component', { class: 'foo', style: 'color:red' }) }}
{# renders as: #}
<div class="foo">
My Component!
</div>
```
### Without
```twig
{# templates/components/my_component.html.twig #}
<div{{ attributes.without('class')) }}>
My Component!
</div>
{# render component #}
{{ component('my_component', { class: 'foo', style: 'color:red' }) }}
{# renders as: #}
<div style="color:red">
My Component!
</div>
```
### Live Components
We removed the `init_live_component()` twig function (**BC BREAK**) and replaced with the `attributes` variable which is always available (even if your component doesn't use `HasAttributesTrait`).
To upgrade, replace all calls to `init_live_component()` with `attributes`:
```diff
- <div {{ init_live_component() }}>
+ <div {{ attributes }}>
```
Commits
-------
d638782 [Twig][Live] add html attributes system
if (!method_exists($componentClass, $defaultAction)) {
92
+
if (!method_exists($metadata->getClass(), $defaultAction)) {
88
93
// todo should this check be in a compiler pass to ensure fails at compile time?
89
-
thrownew \LogicException(sprintf('Live component "%s" requires the default action method "%s".%s', $componentClass, $defaultAction, '__invoke' === $defaultAction ? ' Either add this method or use the DefaultActionTrait' : ''));
94
+
thrownew \LogicException(sprintf('Live component "%s" (%s) requires the default action method "%s".%s', $metadata->getClass(), $componentName, $defaultAction, '__invoke' === $defaultAction ? ' Either add this method or use the DefaultActionTrait' : ''));
0 commit comments