Skip to content

Commit f89eb5d

Browse files
authored
fix(view): attributes for raw elements (#734)
1 parent 613b884 commit f89eb5d

File tree

3 files changed

+80
-26
lines changed

3 files changed

+80
-26
lines changed

src/Tempest/View/src/Elements/ElementFactory.php

Lines changed: 22 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -52,47 +52,45 @@ private function makeElement(DOMNode $node, ?Element $parent): ?Element
5252
);
5353
}
5454

55-
if (
56-
! $node instanceof DOMElement
55+
$attributes = [];
56+
57+
/** @var DOMAttr $attribute */
58+
foreach ($node->attributes as $attribute) {
59+
$name = str($attribute->name)->camel()->toString();
60+
61+
$attributes[$name] = $attribute->value;
62+
}
63+
64+
if (! $node instanceof DOMElement
5765
|| $node->tagName === 'pre'
58-
|| $node->tagName === 'code'
59-
) {
60-
return new RawElement($node->ownerDocument->saveHTML($node));
66+
|| $node->tagName === 'code') {
67+
$content = '';
68+
foreach ($node->childNodes as $child) {
69+
$content .= $node->ownerDocument->saveHTML($child);
70+
}
71+
72+
return new RawElement(
73+
tag: $node->tagName ?? null,
74+
content: $content,
75+
attributes: $attributes,
76+
);
6177
}
6278

6379
if ($viewComponentClass = $this->viewConfig->viewComponents[$node->tagName] ?? null) {
6480
if (! $viewComponentClass instanceof ViewComponent) {
6581
$viewComponentClass = $this->container->get($viewComponentClass);
6682
}
6783

68-
$attributes = [];
69-
70-
/** @var DOMAttr $attribute */
71-
foreach ($node->attributes as $attribute) {
72-
$name = (string)str($attribute->name)->camel();
73-
74-
$attributes[$name] = $attribute->value;
75-
}
76-
7784
$element = new ViewComponentElement(
7885
$this->compiler,
7986
$viewComponentClass,
80-
$attributes
87+
$attributes,
8188
);
8289
} elseif ($node->tagName === 'x-slot') {
8390
$element = new SlotElement(
8491
name: $node->getAttribute('name') ?: 'slot',
8592
);
8693
} else {
87-
$attributes = [];
88-
89-
/** @var DOMAttr $attribute */
90-
foreach ($node->attributes as $attribute) {
91-
$name = (string)str($attribute->name)->camel();
92-
93-
$attributes[$name] = $attribute->value;
94-
}
95-
9694
$element = new GenericElement(
9795
tag: $node->tagName,
9896
attributes: $attributes,

src/Tempest/View/src/Elements/RawElement.php

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,51 @@
44

55
namespace Tempest\View\Elements;
66

7+
use function Tempest\Support\str;
78
use Tempest\View\Element;
89

910
final class RawElement implements Element
1011
{
1112
use IsElement;
1213

1314
public function __construct(
14-
private readonly string $html,
15+
private readonly ?string $tag,
16+
private readonly string $content,
17+
array $attributes,
1518
) {
19+
$this->attributes = $attributes;
1620
}
1721

1822
public function compile(): string
1923
{
20-
return $this->html;
24+
if ($this->tag === null) {
25+
return $this->content;
26+
}
27+
28+
$attributes = [];
29+
30+
foreach ($this->getAttributes() as $name => $value) {
31+
$name = str($name);
32+
33+
if ($name->startsWith(':')) {
34+
$name = ':' . $name->kebab()->toString();
35+
} else {
36+
$name = $name->kebab()->toString();
37+
}
38+
39+
if ($value) {
40+
$attributes[] = $name . '="' . $value . '"';
41+
} else {
42+
$attributes[] = $name;
43+
}
44+
}
45+
46+
$attributes = implode(' ', $attributes);
47+
48+
if ($attributes !== '') {
49+
$attributes = ' ' . $attributes;
50+
}
51+
52+
return "<{$this->tag}{$attributes}>{$this->content}</{$this->tag}>";
2153
}
2254
}

tests/Integration/View/TempestViewRendererDataPassingTest.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,4 +262,28 @@ public function test_boolean_attributes(): void
262262
HTML, value: 'value', selected: false, name: 'name'),
263263
);
264264
}
265+
266+
public function test_expression_attribute_in_raw_element(): void
267+
{
268+
$this->registerViewComponent(
269+
'x-test',
270+
<<<'HTML'
271+
<div><x-slot/></div>
272+
HTML,
273+
);
274+
275+
$html = $this->render(<<<'HTML'
276+
<x-test>
277+
<pre :data-lang="$language"><hello></hello>foo<p>bar</p></pre>
278+
</x-test>
279+
HTML, language: 'php');
280+
281+
$this->assertStringEqualsStringIgnoringLineEndings(
282+
<<<'HTML'
283+
<div><pre data-lang="php"><hello></hello>foo<p>bar</p></pre>
284+
</div>
285+
HTML,
286+
$html
287+
);
288+
}
265289
}

0 commit comments

Comments
 (0)