Files
livewire-material/tests/Feature/InternalComponentsTest.php
T
Andreas Reinhold / reiniandClaude Opus 5 0341f9d4ca Draw the text field's chrome without Tailwind
<x-field> renders data-md-field with its props and parts as data-md-*
attributes (box, control, label, outline, support, counter, trailing
buttons), and field.css moves into material.components on tokens: px
geometry, spacing and state tokens, the 600px breakpoint (plan step 36).
Its icons take a size prop, 24/20/16 by the field's size.

Every control the field wraps now marks itself data-md-field-control,
so the inputs, the pickers, choices, field.js, menu.css's select and
listbox rules and timepicker.css follow the renamed hooks. Browser tests
cover the error icon, the disabled field's hover, the counter and the
width bound from 600px.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qwx5USif3wFFmxtHg5U1g9
2026-09-14 14:08:22 +02:00

75 lines
3.2 KiB
PHP

<?php
use Illuminate\Support\Facades\Blade;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\View;
use NoNameWeb\LivewireMaterial\LivewireMaterialServiceProvider;
/**
* The package's own component names, longest first.
*
* @return list<string>
*/
function packageComponentNames(): array
{
return collect(File::files(LivewireMaterialServiceProvider::componentPath()))
->map(fn (SplFileInfo $file): string => $file->getBasename('.blade.php'))
->sortByDesc(fn (string $name): int => strlen($name))
->values()
->all();
}
it('refers to its own components through its namespace, which no prefix or app component changes', function () {
$names = implode('|', array_map(fn (string $name): string => preg_quote($name, '/'), packageComponentNames()));
$unqualified = collect(File::allFiles(__DIR__.'/../../resources/views'))
->filter(fn (SplFileInfo $file): bool => str_ends_with($file->getFilename(), '.blade.php'))
->flatMap(function (SplFileInfo $file) use ($names): array {
// Comments document usage as an application writes it, and the showcase's examples
// are that usage; neither is compiled as the package's own markup.
$source = preg_replace(['/\{\{--.*?--\}\}/s', "/<<<'BLADE'.*?^\\s*BLADE,/sm"], '', $file->getContents());
preg_match_all('/<\/?x-('.$names.')(?=[\s\/>])/', $source, $matches);
return array_map(fn (string $tag): string => $file->getRelativePathname().': '.$tag, $matches[0]);
})
->values();
expect($unqualified->all())->toBe([]);
});
it('renders components that use others under a prefix', function () {
config(['livewire-material.prefix' => 'm']);
Blade::anonymousComponentPath(LivewireMaterialServiceProvider::componentPath(), 'm');
expect(Blade::render('<x-m::drawer title="Share" with-close-button separator><x-m::input label="Name" clearable /></x-m::drawer>'))
->toContain('aria-label="Close"')
->toContain('role="separator"')
->toContain('data-md-field-clear');
});
it('is not shadowed by an application component of the same name', function () {
$views = sys_get_temp_dir().'/livewire-material-shadow-'.uniqid();
File::ensureDirectoryExists($views.'/components');
File::put($views.'/components/button.blade.php', '<span>the application\'s button</span>');
View::getFinder()->prependLocation($views);
try {
expect(Blade::render('<x-button />'))->toContain('the application\'s button')
->and(Blade::render('<x-drawer title="Share" with-close-button />'))->not->toContain('the application\'s button')
->toContain('aria-label="Close"');
} finally {
File::deleteDirectory($views);
}
});
it('shows the showcase\'s examples as an application with a prefix writes them', function () {
config(['livewire-material.prefix' => 'm']);
Blade::anonymousComponentPath(LivewireMaterialServiceProvider::componentPath(), 'm');
expect(Blade::render('<x-showcase::example title="Buttons" :code="$code" />', ['code' => '<x-button label="Save" />']))
->toContain('&lt;x-m::button label=&quot;Save&quot; /&gt;')
->toContain('Save</span>');
});