-
Notifications
You must be signed in to change notification settings - Fork 11.1k
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
New @attributes blade directive. #52783
base: 11.x
Are you sure you want to change the base?
New @attributes blade directive. #52783
Conversation
Thanks for submitting a PR! Note that draft PR's are not reviewed. If you would like a review, please mark your pull request as ready for review in the GitHub user interface. Pull requests that are abandoned in draft may be closed due to inactivity. |
I like the initial idea (mine) more 😅 Does the idea work with |
Haha, well you would I suppose! my thought is that the second way 'feels' more laravel-like to me, but that's just a personal take obviously. and another BUT - the
In my version, i would suggest that, passing two keys that are the same would either:
@attributes([
'id' => '1',
'id' => '2',
]); // would print id="2" OR
Haven't tested this yet, but i will, if we can detect that it's an instance of the |
src/Illuminate/Collections/Arr.php
Outdated
/** | ||
* Conditionally compile attributes from an array into an HTML attribute string. | ||
* | ||
* @param array $array | ||
* @return string | ||
*/ | ||
public static function toHtmlAttributes($array) | ||
{ | ||
return Collection::make($array)->map(function ($value, $key) { | ||
if ($key) { | ||
return $value ? sprintf('%s', $key) : null; | ||
} elseif ($value instanceof ComponentAttributeBag) { | ||
return collect($value->getAttributes())->map(fn ($value, $key) => sprintf('%s="%s"', $key, $value))->join(' '); | ||
} else { | ||
return sprintf("%s", $value); | ||
} | ||
}) | ||
->implode(" "); | ||
} | ||
|
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 would want to make sure this matches the attribute parsing we do in Vite.
<div {{ Arr::toHtmlAttributes([
'null-value'=> null, // removed
'false-value' => false, // removed
'empty-string-value' => '',
'zero-value' => 0,
'true-value' => true,
'other-key' => 'other-value',
]) }}>
//
<div
empty-string-value=""
zero-value="0"
true-value="true-value"
other-key="other-value"
>
The conditionals and the I wonder if this could feel more at home in Laravel if we encouraged composition with the new With the <button @attributes([
'wire:poll.5s' => when($condition, 'calculate'),
'disabled' => $isDisabled,
'data-foo' => when($foo, 'foo bar'),
])>
// ..
<form wire:poll.5s="calculate" disabled="disabled"> With the <form
@attributes([
'wire:poll.5s' => when($condition, 'calculate'),
'disabled' => $isDisabled,
'data-foo' => when($foo, 'foo bar'),
])
@class([
'px-y',
'mt-10' => $loop->first,
])
>
// ..
<form wire:poll.5s="calculate" disabled="disabled" class="> Then you get lazily evaluation for free as <form @attributes([
'data-foo' => when($foo, fn () => /* ... */),
])> |
using |
@timacdonald yeah I prefer that way as well, will re-work the PR. Did you mean to make the directive name singular? |
are boolean attributes outputted with a "true" value? They should not. https://developer.mozilla.org/en-US/docs/Glossary/Boolean/HTML
If true the attribute should just be written without any value: |
for
Will add this in, thank you! |
My mistake. I updated my snippets to use
They should match what we do for the Vite helper, i.e., Although, the spec is inconsistent with the implementation, e.g, |
My opinion is that they should match
I know technically both are correct, but the one without a value (which are not really needed) feels way nicer, and it's the first option listed on mdn.
True, i have never understood why aria booleans are treated differently compared to other booleans 🫠 |
* @param string $expression | ||
* @return array | ||
*/ | ||
public function reformatAttributeExpressionStringToArray(string $expression) |
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.
@timacdonald could use some pointers here if you don't mind?
For any @attributes
call on a normal HTML element i'm just doing this - which is fairly simple.
For @attributes
calls on slots and custom components, it's tough, because we can't compile into an existing attribute and prefix with :
in the same way we can with @class
, the attributes need to be parsed before compile time, so that they're fully parsed and passed down into the component.
BUT, this doesn't work when functions and
I'd ended up with this, which is taking the @attributes
expression, parsing it using a regex, and turning it back into an array so it can be parsed properly by the new toHtmlAttributes
method, but this isn't going to support things like calls to when
or $variables
properly.
Am i on the right track, or should i look at taking another approach? I'm trying to get my head around blade's compilation order, and the expectations of the output.
Cheers!
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.
Hey, Dan, I don't know a heap about the Blade compiler unfortunately.
I don't imagine that the regex is gonna be the answer...but then again blade is entirely regex so maybe it is?
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.
No worries man, i'll keep plucking at the problem, it feels like this is over-engineered to me, but will keep digging. 👍
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.
Sounds good. Don't take my feedback as anything you must do. Just sharing an opinion.
I'm back, pinching neat ideas from people smarter than me again! - @tpetry had a great idea for an attributes directive on twitter so I thought i'd follow on the heels of the
when
helper and PR this in.Note: I've updated the PR description to better reflect what's being proposed, but i've preserved the original description below.
Progress
@attributes
helper compiles on normal HTML components.null
orfalse
values will result in the attribute not being rendered@attributes
directive.@attributes
directive.@attributes
directive@attributes
directive on custom componentsArr::toHtmlAttributes
method.The
@attributes()
blade directive.Can be used to neatly, and conditionally compose attributes on your HTML elements or components in blade files.
You can also pass the
$attributes
variable that is automatically created for blade component files straight in, and it will traverse and render them, useful for passing attributes down to sub-components if needed.Original PR Description
Why
Can be used to conditionally render attributes on your HTML elements or components in blade files.
Possible variation that might work better but be less readable:
Passing the whole attribute as the key here might be problematic, what might be nice is if you could pass a bunch of
key => value
pairs as the attribute name and value.In this case, any key value pair that has a value of null would be discarded, but and singular value-only entry like
required
above would just be printed.If the
$value
is also not astring
, we could echo out JUST the key, or, if it aligns with most HTML attribute use cases, we could echo out the key again, i.e.disabled="disabled"
.Known Issues
Using this on custom components at the moment appears to spit out the attributes compiled, but prevents the custom component from rendering, i'm looking into this.