<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
75 lines
3.2 KiB
PHP
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('<x-m::button label="Save" />')
|
|
->toContain('Save</span>');
|
|
});
|