Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion src/BladeRenderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public function getTemporaryCachePath(): string
/**
* Render a Blade template string in isolation by freezing and restoring compiler state.
*/
public function render(ComponentNode $component, ComponentSource $source): string
public function render(ComponentNode $component, ComponentSource $source, array $aware = []): string
{
$temporaryCachePath = $this->getTemporaryCachePath();

Expand Down Expand Up @@ -112,6 +112,15 @@ function ($input) {
return [$slot->name => new ComponentSlot($slot->content())];
});

$awareData = Arr::mapWithKeys($aware, function (Attribute $attribute) {
return [$attribute->name => $attribute->getStaticValue()];
});

// Inherited @aware values reach the component the way they do at render --
// through the data stack, under the component's own frame -- rather than by
// being merged into its attribute bag. A component that asks whether a key
// was written on its tag then gets the same answer folded and unfolded.
$this->runtime->pushData($awareData);
$this->runtime->pushData($attributes);
$this->runtime->pushSlots($slots);

Expand All @@ -131,6 +140,7 @@ function ($input) {
ob_end_clean();
}

$this->runtime->popData();
$this->runtime->popData();
$this->manager->stopFolding();

Expand Down
11 changes: 7 additions & 4 deletions src/Folder/Foldable.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ class Foldable
protected array $slotByPlaceholder = [];
protected int $placeholderIndex = 0;

/** @var array<string, Attribute> Inherited @aware values, kept out of the component's own bag. */
protected array $awareAttributes = [];

protected ComponentNode $renderable;
protected string $html;

Expand Down Expand Up @@ -52,7 +55,7 @@ public function fold(): string
$this->setupSlots();
$this->mergeAwareProps();

$this->html = $this->renderer->render($this->renderable, $this->source);
$this->html = $this->renderer->render($this->renderable, $this->source, $this->awareAttributes);

$this->processUncompiledAttributes();
$this->restorePlaceholders();
Expand Down Expand Up @@ -165,14 +168,14 @@ protected function mergeAwareProps(): void

$this->attributeByPlaceholder[$placeholder] = $attribute;

$this->renderable->attributes[$prop] = new Attribute(
$this->awareAttributes[$prop] = new Attribute(
name: $prop,
value: $placeholder,
propName: $prop,
dynamic: false,
);
} else {
$this->renderable->attributes[$prop] = new Attribute(
$this->awareAttributes[$prop] = new Attribute(
name: $attribute->name,
value: $attribute->value,
propName: $attribute->propName,
Expand All @@ -187,7 +190,7 @@ protected function mergeAwareProps(): void
// skip adding the attribute. This lets @aware and @props handle defaults
// at runtime, matching the non-folded behavior. Adding an attribute with
// null value would render as prop="" in HTML, corrupting null to empty string.
$this->renderable->attributes[$prop] = new Attribute(
$this->awareAttributes[$prop] = new Attribute(
name: $prop,
value: $default,
propName: $prop,
Expand Down
14 changes: 14 additions & 0 deletions tests/ComparisonTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,20 @@
BLADE
));

test('foldable aware read back off the attribute bag', fn () => compare(<<<'BLADE'
<x-foldable.wrapper type="number">
<x-foldable.input-aware-bag />
</x-foldable.wrapper>
BLADE
));

test('foldable aware written on the tag itself', fn () => compare(<<<'BLADE'
<x-foldable.wrapper type="number">
<x-foldable.input-aware-bag type="email" />
</x-foldable.wrapper>
BLADE
));

test('foldable boolean attributes', fn () => compare(<<<'BLADE'
<x-foldable.input :readonly="$readonly" />
BLADE,
Expand Down
18 changes: 18 additions & 0 deletions tests/fixtures/views/components/foldable/input-aware-bag.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
@blaze(fold: true)

{{-- A component that has to tell an attribute written on its own tag from one it
inherited. The field name on a form control is the usual case: it decides
whether the control owns its own validation message or whether the field
around it does. The bag is snapshotted and restored because @aware consumes
the key, and the value still has to reach the element. --}}
@php
$__bag = $attributes->getAttributes();
@endphp

@aware(['type' => 'text'])

@php
$attributes->setAttributes($__bag);
@endphp

<input type="{{ $type }}" data-source="{{ $attributes->get('type') === null ? 'inherited' : 'own' }}" >
Loading