Skip to content

Commit 47a9ad3

Browse files
authored
refactor(view): attach tokens to relevant elements for raw slot content support (#1428)
1 parent 051078b commit 47a9ad3

File tree

9 files changed

+100
-22
lines changed

9 files changed

+100
-22
lines changed

packages/view/src/Elements/ElementFactory.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ private function makeElement(Token $token, ?Element $parent): ?Element
6363
}
6464

6565
if (! $token->tag || $token->type === TokenType::COMMENT || $token->type === TokenType::PHP) {
66-
return new RawElement(tag: null, content: $token->compile());
66+
return new RawElement(token: $token, tag: null, content: $token->compile());
6767
}
6868

6969
$attributes = $token->htmlAttributes;
@@ -74,6 +74,7 @@ private function makeElement(Token $token, ?Element $parent): ?Element
7474

7575
if ($token->tag === 'code' || $token->tag === 'pre') {
7676
return new RawElement(
77+
token: $token,
7778
tag: $token->tag,
7879
content: $token->compileChildren(),
7980
attributes: $attributes,
@@ -91,22 +92,26 @@ private function makeElement(Token $token, ?Element $parent): ?Element
9192
}
9293

9394
$element = new ViewComponentElement(
95+
token: $token,
9496
environment: $this->appConfig->environment,
9597
compiler: $this->compiler,
9698
viewComponent: $viewComponentClass,
9799
attributes: $attributes,
98100
);
99101
} elseif ($token->tag === 'x-template') {
100102
$element = new TemplateElement(
103+
token: $token,
101104
attributes: $attributes,
102105
);
103106
} elseif ($token->tag === 'x-slot') {
104107
$element = new SlotElement(
108+
token: $token,
105109
name: $token->getAttribute('name') ?? Slot::DEFAULT,
106110
attributes: $attributes,
107111
);
108112
} else {
109113
$element = new GenericElement(
114+
token: $token,
110115
tag: $token->tag,
111116
attributes: $attributes,
112117
);

packages/view/src/Elements/GenericElement.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,17 @@
55
namespace Tempest\View\Elements;
66

77
use Tempest\View\Element;
8+
use Tempest\View\Parser\Token;
9+
use Tempest\View\WithToken;
810

911
use function Tempest\Support\Html\is_void_tag;
10-
use function Tempest\Support\str;
1112

12-
final class GenericElement implements Element
13+
final class GenericElement implements Element, WithToken
1314
{
1415
use IsElement;
1516

1617
public function __construct(
18+
public readonly Token $token,
1719
private readonly string $tag,
1820
array $attributes,
1921
) {

packages/view/src/Elements/RawElement.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,17 @@
55
namespace Tempest\View\Elements;
66

77
use Tempest\View\Element;
8+
use Tempest\View\Parser\Token;
9+
use Tempest\View\WithToken;
810

911
use function Tempest\Support\str;
1012

11-
final class RawElement implements Element
13+
final class RawElement implements Element, WithToken
1214
{
1315
use IsElement;
1416

1517
public function __construct(
18+
public readonly Token $token,
1619
private readonly ?string $tag,
1720
private readonly string $content,
1821
array $attributes = [],

packages/view/src/Elements/SlotElement.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,15 @@
55
namespace Tempest\View\Elements;
66

77
use Tempest\View\Element;
8+
use Tempest\View\Parser\Token;
9+
use Tempest\View\WithToken;
810

9-
final class SlotElement implements Element
11+
final class SlotElement implements Element, WithToken
1012
{
1113
use IsElement;
1214

1315
public function __construct(
16+
public readonly Token $token,
1417
public readonly string $name,
1518
array $attributes = [],
1619
) {

packages/view/src/Elements/TemplateElement.php

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,17 @@
55
namespace Tempest\View\Elements;
66

77
use Tempest\View\Element;
8+
use Tempest\View\Parser\Token;
9+
use Tempest\View\WithToken;
810

9-
final class TemplateElement implements Element
11+
final class TemplateElement implements Element, WithToken
1012
{
1113
use IsElement;
1214

13-
public function __construct(array $attributes = [])
14-
{
15+
public function __construct(
16+
public readonly Token $token,
17+
array $attributes = [],
18+
) {
1519
$this->attributes = $attributes;
1620
}
1721

packages/view/src/Elements/ViewComponentElement.php

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,19 +11,22 @@
1111
use Tempest\View\Element;
1212
use Tempest\View\Parser\TempestViewCompiler;
1313
use Tempest\View\Parser\TempestViewParser;
14+
use Tempest\View\Parser\Token;
1415
use Tempest\View\Slot;
1516
use Tempest\View\ViewComponent;
17+
use Tempest\View\WithToken;
1618

1719
use function Tempest\Support\arr;
1820
use function Tempest\Support\str;
1921

20-
final class ViewComponentElement implements Element
22+
final class ViewComponentElement implements Element, WithToken
2123
{
2224
use IsElement;
2325

2426
private array $dataAttributes;
2527

2628
public function __construct(
29+
public readonly Token $token,
2730
private readonly Environment $environment,
2831
private readonly TempestViewCompiler $compiler,
2932
private readonly ViewComponent $viewComponent,
@@ -47,19 +50,19 @@ public function getSlots(): ImmutableArray
4750
{
4851
$slots = arr();
4952

50-
$default = [];
53+
$defaultTokens = [];
5154

52-
foreach ($this->getChildren() as $child) {
53-
if ($child instanceof SlotElement) {
54-
$slot = Slot::fromElement($child);
55+
foreach ($this->token->children as $child) {
56+
if ($child->tag === 'x-slot') {
57+
$slot = Slot::named($child);
5558

5659
$slots[$slot->name] = $slot;
5760
} else {
58-
$default[] = $child;
61+
$defaultTokens[] = $child;
5962
}
6063
}
6164

62-
$slots[Slot::DEFAULT] = Slot::fromElement(new CollectionElement($default));
65+
$slots[Slot::DEFAULT] = Slot::default(...$defaultTokens);
6366

6467
return $slots;
6568
}
@@ -154,7 +157,9 @@ public function compile(): string
154157
return $this->environment->isProduction() ? '' : ('<!--' . $matches[0] . '-->');
155158
}
156159

157-
$compiled = $slot->content;
160+
$slotElement = $this->getSlotElement($slot->name);
161+
162+
$compiled = $slotElement?->compile() ?? '';
158163

159164
// There's no default slot content, but there's a default value in the view component
160165
if (trim($compiled) === '') {
@@ -167,4 +172,25 @@ public function compile(): string
167172

168173
return $this->compiler->compile($compiled->toString());
169174
}
175+
176+
private function getSlotElement(string $name): SlotElement|CollectionElement|null
177+
{
178+
$defaultElements = [];
179+
180+
foreach ($this->getChildren() as $childElement) {
181+
if ($childElement instanceof SlotElement && $childElement->name === $name) {
182+
return $childElement;
183+
}
184+
185+
if (! ($childElement instanceof SlotElement)) {
186+
$defaultElements[] = $childElement;
187+
}
188+
}
189+
190+
if ($name === Slot::DEFAULT) {
191+
return new CollectionElement($defaultElements);
192+
}
193+
194+
return null;
195+
}
170196
}

packages/view/src/Parser/Token.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
final class Token
1010
{
11+
/** @var \Tempest\View\Parser\Token[] */
1112
private(set) array $children = [];
1213

1314
private(set) ?Token $parent = null;

packages/view/src/Slot.php

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@
44

55
namespace Tempest\View;
66

7-
use Tempest\View\Elements\CollectionElement;
8-
use Tempest\View\Elements\SlotElement;
7+
use Tempest\View\Parser\Token;
98

109
final class Slot
1110
{
@@ -22,12 +21,33 @@ public function __get(string $name): mixed
2221
return $this->attributes[$name] ?? null;
2322
}
2423

25-
public static function fromElement(SlotElement|CollectionElement $element): self
24+
public static function named(Token $token): self
2625
{
26+
$name = $token->getAttribute('name');
27+
$attributes = $token->htmlAttributes;
28+
$content = $token->compileChildren();
29+
30+
return new self(
31+
name: $name,
32+
attributes: $attributes,
33+
content: $content,
34+
);
35+
}
36+
37+
public static function default(Token ...$tokens): self
38+
{
39+
$name = Slot::DEFAULT;
40+
$attributes = [];
41+
$content = '';
42+
43+
foreach ($tokens as $token) {
44+
$content .= $token->compile();
45+
}
46+
2747
return new self(
28-
name: $element->name ?? self::DEFAULT,
29-
attributes: $element->getAttributes(),
30-
content: $element->compile(),
48+
name: $name,
49+
attributes: $attributes,
50+
content: $content,
3151
);
3252
}
3353

packages/view/src/WithToken.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Tempest\View;
6+
7+
use Tempest\View\Parser\Token;
8+
9+
interface WithToken
10+
{
11+
public Token $token {
12+
get;
13+
}
14+
}

0 commit comments

Comments
 (0)