Cut duplicated and speculative code across the package

An over-engineering audit of the whole tree, applied in five reviewed
batches. Behaviour stays the same except where UPGRADE.md says otherwise.

PHP: the showcase and error-page stylesheets are prebuilt into
resources/dist by bin/stylesheets.mjs, through Vite's own postcss-import
(first occurrence kept, the order an application's build gives), instead
of Stylesheets::bundle() inlining imports on every request; only the
import walk DesignGuard needs stays. SchemeStylesheet::withProfiles()
replaces three copies of the scheme-plus-profiles loop, material:scheme
leaves spec and contrast checks to the node script that already made
them, and the error page's scheme cache, the hashed view namespace, the
translations path with no lang/ folder and DesignGuard's 1.x-name hints
are gone.

JS: the androidx shape port progress.js and both bin scripts each carried
lives once in resources/js/shapes.js (the generated SVGs are unchanged);
util.js holds ringIndex(), ms(), reopenGuard() and remember(), which
were written out several times; listeners are released through
AbortController; tooltip.js's hoverPopover() serves the rich tooltip too.

CSS: every rule for an element inside the navigation rail queries
`--md-navigation-rail-value` instead of repeating the seven collapsed
conditions under five media branches; badge, alert, progress, slider and
button read one non-inheriting colour-role table (components/color.css);
the dialog chrome, the submenu's popover chrome, the chip's state layer
and touch target, and the visually-hidden inputs use the shared rules
they copied; foundation/tokens.css is folded into foundation.css.

Views: Support\Field and Support\Link replace the error-key, bound-value
and link-attribute blocks copied into the fields and link components;
the timepicker period group, the menu filter and the showcase head are
partials; the datepicker's steppers and entry fields are loops; component
docblocks no longer restate SKILL.md.

Tests and tooling: one dataset-driven ComponentStylesheetsTest replaces
four per-group files, DesignGuardTest and the layout-component tests use
datasets, browser tests share one ready() helper, CSS parsing lives in
ComponentStylesheet alone. docs/audits and the finding IDs citing it are
removed, as are pestphp/pest-plugin-laravel, the unused composer scripts
and check:font; the lint job runs in the feature job, which now installs
node packages so the prebuilt-stylesheet staleness test runs in CI.

Feature suite 1177 passed, Chrome browser suite 299 passed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Andreas Reinhold / reini
2026-09-17 19:29:21 +02:00
co-authored by Claude Opus 5
parent 471d927e64
commit 247c596c3a
233 changed files with 16635 additions and 10579 deletions
+9 -11
View File
@@ -1,10 +1,10 @@
<?php
use Illuminate\Support\Facades\Blade;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Route;
use Livewire\Component;
use Livewire\Livewire;
use NoNameWeb\LivewireMaterial\Support\Stylesheets;
/**
* The central claims of the `@layer material` design (plan step 42, docs/plans/material-3-alignment.md
@@ -17,8 +17,7 @@ use NoNameWeb\LivewireMaterial\Support\Stylesheets;
*/
function cascadeReady(mixed $page): mixed
{
return $page->waitForEvent('networkidle')
->assertScript("document.readyState === 'complete' && typeof window.Alpine !== 'undefined' && typeof window.Livewire !== 'undefined'");
return ready($page);
}
it('lets an application\'s unlayered rule beat a component default', function () {
@@ -73,14 +72,13 @@ it('lets [hidden] beat a component\'s display', function () {
it('keeps the layer order even when a component file is imported before the foundation', function () {
// Every package stylesheet opens with the same full `@layer` statement (plan step 33), so the
// order it establishes holds whichever file a page reaches first — button.css's own copy of it,
// reached here before foundation.css's. Inlined through Stylesheets::bundle(), the same PHP
// bundler the showcase and the error page's fallback use, in that deliberate order: button.css's
// rules, in `material.components`, physically precede foundation.css's reset, in
// `material.reset` — and still lose the layer priority fight, so the button's own padding
// survives the reset's `padding: 0`.
$css = Stylesheets::bundle([__DIR__.'/../../resources/css/components/button.css'])
.Stylesheets::bundle([__DIR__.'/../../resources/css/foundation.css']);
// order it establishes holds whichever file a page reaches first — the error layout's copy of
// it, reached here before the foundation's. The two prebuilt error-page stylesheets, in that
// deliberate order: the layout's bundle, whose button.css rules sit in `material.components`,
// physically precedes the fallback's foundation reset, in `material.reset` — and still loses
// the layer priority fight, so the button's own padding survives the reset's `padding: 0`.
$css = File::get(__DIR__.'/../../resources/dist/error-page.css')
.File::get(__DIR__.'/../../resources/dist/error-page-fallback.css');
// Served as its own response, not inlined through Blade::render(): CSS's own `@media`,
// `@layer` and `@import` would otherwise reach Blade's directive compiler along with the page.