Skip to content

Commit

Permalink
add support for appendable component attributes
Browse files Browse the repository at this point in the history
  • Loading branch information
taylorotwell committed Oct 1, 2020
1 parent fbddbd2 commit 09b887b
Show file tree
Hide file tree
Showing 5 changed files with 91 additions and 16 deletions.
13 changes: 13 additions & 0 deletions src/Illuminate/View/AppendableAttributeValue.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

namespace Illuminate\View;

class AppendableAttributeValue
{
public $value;

public function __construct($value)
{
$this->value = $value;
}
}
77 changes: 61 additions & 16 deletions src/Illuminate/View/ComponentAttributeBag.php
Original file line number Diff line number Diff line change
Expand Up @@ -171,31 +171,76 @@ public function exceptProps($keys)
*/
public function merge(array $attributeDefaults = [], $escape = true)
{
$attributes = [];

$attributeDefaults = array_map(function ($value) use ($escape) {
if (! $escape || is_object($value) || is_null($value) || is_bool($value)) {
return $value;
}

return e($value);
return $this->shouldEscapeAttributeValue($escape, $value)
? e($value)
: $value;
}, $attributeDefaults);

foreach ($this->attributes as $key => $value) {
if ($key !== 'class') {
$attributes[$key] = $value;
[$appendableAttributes, $nonAppendableAttributes] = collect($this->attributes)
->partition(function ($value, $key) use ($attributeDefaults) {
return $key === 'class' ||
(isset($attributeDefaults[$key]) &&
$attributeDefaults[$key] instanceof AppendableAttributeValue);
});

continue;
}
$attributes = $appendableAttributes->mapWithKeys(function ($value, $key) use ($attributeDefaults, $escape) {
$defaultsValue = isset($attributeDefaults[$key]) && $attributeDefaults[$key] instanceof AppendableAttributeValue
? $this->resolveAppendableAttributeDefault($attributeDefaults, $key, $escape)
: ($attributeDefaults[$key] ?? '');

$attributes[$key] = implode(' ', array_unique(
array_filter([$attributeDefaults[$key] ?? '', $value])
));
}
return [$key => implode(' ', array_unique(array_filter([$defaultsValue, $value])))];
})->merge($nonAppendableAttributes)->all();

return new static(array_merge($attributeDefaults, $attributes));
}

/**
* Determine if the specific attribute value should be escaped.
*
* @param bool $escape
* @param mixed $value
* @return bool
*/
protected function shouldEscapeAttributeValue($escape, $value)
{
if (! $escape) {
return false;
}

return ! is_object($value) &&
! is_null($value) &&
! is_bool($value);
}

/**
* Create a new appendable attribute value.
*
* @param mixed $value
* @return \Illuminate\View\AppendableAttributeValue
*/
public function appends($value)
{
return new AppendableAttributeValue($value);
}

/**
* Resolve an appendable attribute value default value.
*
* @param array $attributeDefaults
* @param string $key
* @param bool $escape
* @return mixed
*/
protected function resolveAppendableAttributeDefault($attributeDefaults, $key, $escape)
{
if ($this->shouldEscapeAttributeValue($escape, $value = $attributeDefaults[$key]->value)) {
$value = e($value);
}

return $value;
}

/**
* Get all of the raw attributes.
*
Expand Down
9 changes: 9 additions & 0 deletions tests/Integration/View/BladeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,15 @@ public function test_rendering_the_same_dynamic_component_with_different_attribu
</span>', trim($view));
}

public function test_appendable_attributes()
{
$view = View::make('uses-appendable-panel', ['name' => 'Taylor'])->render();

$this->assertEquals('<div class="mt-4 bg-gray-100" data-controller="inside-controller outside-controller" foo="bar">
Hello Taylor
</div>', trim($view));
}

protected function getEnvironmentSetUp($app)
{
$app['config']->set('view.paths', [__DIR__.'/templates']);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
@props(['name'])

<div {{ $attributes->merge(['class' => 'mt-4', 'data-controller' => $attributes->appends('inside-controller')]) }}>
Hello {{ $name }}
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<x-appendable-panel class="bg-gray-100" :name="$name" data-controller="outside-controller" foo="bar">
Panel contents
</x-appendable-panel>

0 comments on commit 09b887b

Please sign in to comment.