Skip to content

Commit 3483fe4

Browse files
brendtinnocenzi
andauthored
feat(view)!: support overriding vendor view components (#1439)
Co-authored-by: Enzo Innocenzi <[email protected]>
1 parent c6237db commit 3483fe4

File tree

47 files changed

+435
-380
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+435
-380
lines changed

packages/console/src/Components/Interactive/MultipleChoiceComponent.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ private function getControls(): array
7373
...(
7474
$this->bufferEnabled
7575
? [
76-
'esc' => 'select',
76+
'esc or /' => 'select',
7777
] : [
7878
'/' => 'filter',
7979
'space' => 'select',
@@ -110,6 +110,11 @@ public function input(string $key): void
110110
$this->bufferEnabled = true;
111111
$this->updateQuery();
112112

113+
return;
114+
} elseif ($this->bufferEnabled && $key === '/') {
115+
$this->bufferEnabled = false;
116+
$this->updateQuery();
117+
113118
return;
114119
}
115120

packages/console/src/Components/Interactive/SingleChoiceComponent.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ private function getControls(): array
7474
$controls = [];
7575

7676
if ($this->bufferEnabled) {
77-
$controls['esc'] = 'select';
77+
$controls['esc or /'] = 'select';
7878
} else {
7979
$controls['/'] = 'filter';
8080
$controls['space'] = 'select';
@@ -114,6 +114,10 @@ public function input(string $key): void
114114
if (! $this->bufferEnabled && $key === '/') {
115115
$this->bufferEnabled = true;
116116

117+
return;
118+
} elseif ($this->bufferEnabled && $key === '/') {
119+
$this->bufferEnabled = false;
120+
117121
return;
118122
}
119123

packages/discovery/src/DiscoveryLocation.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public function __construct(
2323

2424
public function isVendor(): bool
2525
{
26-
return str_contains($this->path, '/vendor/') || str_contains($this->path, '\\vendor\\');
26+
return str_contains($this->path, '/vendor/') || str_contains($this->path, '\\vendor\\') || str_starts_with($this->namespace, 'Tempest');
2727
}
2828

2929
public function toClassName(string $path): string

packages/view/src/Components/AnonymousViewComponent.php

Lines changed: 0 additions & 27 deletions
This file was deleted.

packages/view/src/Components/DynamicViewComponent.php

Lines changed: 0 additions & 69 deletions
This file was deleted.
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
/**
3+
* @var string|null $title The webpage's title
4+
*/
5+
?>
6+
7+
<html lang="en" class="h-dvh flex flex-col scroll-smooth">
8+
<head>
9+
<title>{{ $title ?? 'Tempest' }}</title>
10+
11+
<meta charset="UTF-8"/>
12+
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
13+
14+
<x-slot name="head"/>
15+
16+
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
17+
</head>
18+
<body class="flex flex-col h-full antialiased">
19+
<x-slot/>
20+
<x-slot name="scripts"/>
21+
</body>
22+
</html>
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
/**
3+
* @var string $is
4+
* @var \Tempest\Support\Arr\ImmutableArray $attributes
5+
*/
6+
7+
use Tempest\View\Renderers\TempestViewRenderer;
8+
use Tempest\View\Slot;
9+
10+
use function Tempest\get;
11+
use function Tempest\view;
12+
13+
$attributeString = $attributes
14+
->map(fn (string $value, string $key) => "{$key}=\"{$value}\"")
15+
->implode(' ');
16+
17+
$content = $slots[Slot::DEFAULT]->content ?? '';
18+
19+
$template = sprintf(<<<'HTML'
20+
<%s %s>
21+
%s
22+
</%s>
23+
HTML, $is, $attributeString, $content, $is);
24+
25+
$html = get(TempestViewRenderer::class)->render(view($template, ...$this->data));
26+
?>
27+
28+
{!! $html !!}

packages/view/src/Elements/ElementFactory.php

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
use Tempest\View\Parser\Token;
1414
use Tempest\View\Parser\TokenType;
1515
use Tempest\View\Slot;
16-
use Tempest\View\ViewComponent;
1716
use Tempest\View\ViewConfig;
1817

1918
final class ElementFactory
@@ -82,14 +81,6 @@ private function makeElement(Token $token, ?Element $parent): ?Element
8281
}
8382

8483
if ($viewComponentClass = $this->viewConfig->viewComponents[$token->tag] ?? null) {
85-
if ($token->getAttribute('is') || $token->getAttribute(':is')) {
86-
$viewComponentClass = new DynamicViewComponent($token);
87-
}
88-
89-
if (! ($viewComponentClass instanceof ViewComponent)) {
90-
$viewComponentClass = $this->container->get($viewComponentClass);
91-
}
92-
9384
$element = new ViewComponentElement(
9485
token: $token,
9586
environment: $this->appConfig->environment,

packages/view/src/Elements/ViewComponentElement.php

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ final class ViewComponentElement implements Element, WithToken
3030

3131
private ImmutableArray $scopedVariables;
3232

33+
private ImmutableArray $viewComponentAttributes;
34+
3335
public function __construct(
3436
public readonly Token $token,
3537
private readonly Environment $environment,
@@ -38,6 +40,7 @@ public function __construct(
3840
array $attributes,
3941
) {
4042
$this->attributes = $attributes;
43+
$this->viewComponentAttributes = arr($attributes);
4144

4245
$this->dataAttributes = arr($attributes)
4346
->filter(fn (string $_, string $key) => ! str_starts_with($key, ':'))
@@ -91,7 +94,7 @@ public function compile(): string
9194
{
9295
$slots = $this->getSlots();
9396

94-
$compiled = str($this->viewComponent->compile($this));
97+
$compiled = str($this->viewComponent->contents);
9598

9699
// Fallthrough attributes
97100
$compiled = $compiled
@@ -148,16 +151,17 @@ public function compile(): string
148151
// Close and call the current scope
149152
sprintf(
150153
'<?php })(%s, %s %s %s %s) ?>',
151-
'attributes: ' .
152-
ViewObjectExporter::export($this->dataAttributes->mapWithKeys(fn (mixed $value, string $key) => yield str($key)->kebab()->toString() => $value)),
154+
'attributes: ' . ViewObjectExporter::export($this->viewComponentAttributes),
153155
'slots: ' . ViewObjectExporter::export($slots),
154156
$this->dataAttributes->isNotEmpty()
155157
? (', ' . $this->dataAttributes->map(fn (mixed $value, string $key) => "{$key}: " . ViewObjectExporter::exportValue($value))->implode(', '))
156158
: '',
157159
$this->expressionAttributes->isNotEmpty()
158160
? (', ' . $this->expressionAttributes->map(fn (mixed $value, string $key) => "{$key}: " . $value)->implode(', '))
159161
: '',
160-
$this->scopedVariables->isNotEmpty() ? (', ' . $this->scopedVariables->map(fn (string $name) => "{$name}: \${$name}")->implode(', ')) : '',
162+
$this->scopedVariables->isNotEmpty()
163+
? (', ' . $this->scopedVariables->map(fn (string $name) => "{$name}: \${$name}")->implode(', '))
164+
: '',
161165
),
162166
);
163167

packages/view/src/Exceptions/ViewComponentWasAlreadyRegistered.php

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

77
use Exception;
8-
use Tempest\Reflection\ClassReflector;
9-
use Tempest\View\Components\AnonymousViewComponent;
8+
use Tempest\View\ViewComponent;
109

1110
final class ViewComponentWasAlreadyRegistered extends Exception
1211
{
13-
public function __construct(
14-
string $name,
15-
ClassReflector|AnonymousViewComponent $pending,
16-
string|AnonymousViewComponent $existing,
17-
) {
12+
public function __construct(ViewComponent $pending, ViewComponent $existing)
13+
{
1814
$message = sprintf(
19-
"Could not register view component `{$name}` from `%s`, because a component with the same name already exists in `%s`",
20-
($pending instanceof AnonymousViewComponent) ? $pending->file : $pending->getName(),
21-
($existing instanceof AnonymousViewComponent) ? $existing->file : $existing,
15+
'Could not register view component `%s` from `%s`, because a component with the same name already exists in `%s`',
16+
$pending->name,
17+
$pending->file,
18+
$existing->file,
2219
);
2320

2421
parent::__construct($message);

0 commit comments

Comments
 (0)