path => contents */ function modalViews(): array { $views = []; foreach (File::allFiles(app_path('Livewire')) as $file) { if (! str_contains($file->getContents(), 'extends ModalComponent')) { continue; } $kebab = strtolower((string) preg_replace('/([a-z0-9])([A-Z])/', '$1-$2', $file->getFilenameWithoutExtension())); $folder = str_contains($file->getRelativePath(), 'Admin') ? 'admin/' : ''; $path = resource_path('views/livewire/'.$folder.$kebab.'.blade.php'); if (File::exists($path)) { $views[$folder.$kebab.'.blade.php'] = File::get($path); } } return $views; } it('caps the panel once, for every modal there is', function () { // In the published package view, so no modal can opt out of it and none has // to remember to. dvh rather than vh: on a phone the browser's own chrome // counts towards vh, which is exactly the case where the last centimetre // decides whether the button is reachable. $wrapper = File::get(resource_path('views/vendor/wire-elements-modal/modal.blade.php')); expect($wrapper)->toContain('max-h-[calc(100dvh-') ->toContain('flex-col') ->toContain('overflow-hidden') // The flex child has to be allowed to shrink, or capping the panel // achieves nothing at all. ->toContain('min-h-0'); }); it('keeps the header and the footer out of the scroll region', function () { $modal = File::get(resource_path('views/components/ui/modal.blade.php')); expect($modal)->toContain('shrink-0') ->toContain('overflow-y-auto') // min-h-0 on the body is the line that makes the overflow engage. ->toContain('min-h-0 flex-1 overflow-y-auto') // Reaching the end of the body must not start scrolling the page behind // the backdrop. ->toContain('overscroll-contain'); }); it('builds every modal with a field through the component', function () { // The criterion is the field, not the line count: a two-line confirmation // with one button has nothing that needs to stay put, and converting those // would be churn. The moment somebody adds an input to one, this fails and // says so. $offenders = []; foreach (modalViews() as $name => $body) { $hasField = preg_match('/