Report a colour utility on the application's own theme colour in the design guard
The guard knew M3's roles and Tailwind's palette, so `bg-off-plan`, `text-sport-run`, `from-brand` or `border-l-zone-4` - colours an application's own Tailwind theme named before 2.0.0 - were the leftovers its count never showed, though none has compiled since. After every other family, a class-list token shaped like a colour utility on a name that starts with a letter is now reported with the application's own `var(--...)` as its replacement (`color-mix()` with an opacity), unless the application's CSS declares the class. So that none of Tailwind's own utilities on those prefixes reads as a theme colour, each one Tailwind 4.2 lists is now named by its family: `border-collapse`, `border-spacing-*`, the block borders `border-bs`/ `border-be`, `bg-blend-*` and the other background positions and angles, gradient stops, `fill-none`/`stroke-*`, `text-shadow-*`, `shadow-inner`, `accent-auto`, `inherit`/`initial` as colour keywords, and the `mauve`, `olive`, `mist` and `taupe` palettes; only `inset-ring-*` is still not read. BoostVocabularyTest no longer reads a span holding a single property, prop or role name (`border-color`, `placeholder-value`, `outline-variant`) as a class list. A fixture test covers the theme colours and the Tailwind names beside them. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
394c9326ac
commit
613ac20013
@@ -1,6 +1,7 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\File;
|
||||
use Illuminate\Support\Str;
|
||||
use NoNameWeb\LivewireMaterial\Support\Stylesheets;
|
||||
use NoNameWeb\LivewireMaterial\Testing\DesignGuard;
|
||||
|
||||
@@ -77,16 +78,58 @@ function boostTextAsCode(string $text): array
|
||||
return ['view' => implode("\n", $view), 'css' => implode("\n", $css)];
|
||||
}
|
||||
|
||||
/**
|
||||
* The hyphenated names the texts also write alone in a span for something that is not a class:
|
||||
* every property the package's stylesheets declare (`border-color`), every component prop
|
||||
* (`placeholder-value`) and every colour role (`outline-variant`). Each is shaped like a colour
|
||||
* utility on a name the guard does not know, which is what an application's own theme colour
|
||||
* (`bg-brand`) looks like.
|
||||
*
|
||||
* @return array<string, true>
|
||||
*/
|
||||
function boostNamesThatAreNotClasses(): array
|
||||
{
|
||||
static $names = null;
|
||||
|
||||
if ($names !== null) {
|
||||
return $names;
|
||||
}
|
||||
|
||||
$names = [];
|
||||
$root = __DIR__.'/../../resources';
|
||||
|
||||
foreach (File::allFiles("{$root}/css") as $file) {
|
||||
preg_match_all('/(?<![\w-])([a-z][a-z-]*-[a-z-]+)\s*:\s*[^;{}]*[;}]|--md-sys-color-([a-z-]+)/', $file->getContents(), $matches);
|
||||
|
||||
foreach ([...$matches[1], ...$matches[2]] as $name) {
|
||||
$names[$name] = true;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (File::files("{$root}/views/components") as $file) {
|
||||
if (preg_match('/@props\(\[(.*?)\]\)/s', $file->getContents(), $props) === 1) {
|
||||
preg_match_all("/^\s*'(\w+)'/m", $props[1], $keys);
|
||||
|
||||
foreach ($keys[1] as $key) {
|
||||
$names[Str::kebab($key)] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $names;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether an inline span reads as a class list. Not: a CSS declaration (`font: var(…)`), a
|
||||
* command (`php artisan …`), or a single bare word, which is as often a role, prop or value
|
||||
* (`outline`, `link`, `hidden`) as a utility.
|
||||
* command (`php artisan …`), a single bare word, which is as often a role, prop or value
|
||||
* (`outline`, `link`, `hidden`) as a utility, or a single property, prop or role name
|
||||
* (`border-color`, `placeholder-value`, `outline-variant`).
|
||||
*/
|
||||
function boostSpanIsClassList(string $span): bool
|
||||
{
|
||||
$tokens = preg_split('/\s+/', trim($span));
|
||||
|
||||
if (count($tokens) === 1 && preg_match('/[-:]/', $tokens[0]) !== 1) {
|
||||
if (count($tokens) === 1 && (preg_match('/[-:]/', $tokens[0]) !== 1 || isset(boostNamesThatAreNotClasses()[$tokens[0]]))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -285,6 +285,57 @@ it('exempts a class the application\'s own CSS declares, even when it is Tailwin
|
||||
]);
|
||||
});
|
||||
|
||||
it('reports a colour utility on the application\'s own theme colour, and a Tailwind utility of the same prefix as its own family', function () {
|
||||
$violations = fixtureRelative(DesignGuard::scan(realpath(GUARD_FIXTURES.'/tailwind/theme-colours.blade.php'))->violations());
|
||||
$theme = fn (string $token, string $name, string $use = '`var(--…)`'): string => "Tailwind colour utility `{$token}` compiles to nothing — `{$name}` is neither an M3 role nor a Tailwind colour, so it named a colour of the application's own theme: use {$use} in your own CSS";
|
||||
$tint = '`color-mix(in srgb, var(--…) <n>%, transparent)`';
|
||||
$line = 'a line is `<x-divider>` or `<x-surface outlined>`; any other border is your own CSS, in `var(--md-sys-color-outline-variant)`';
|
||||
$outline = "M3's focus indicator is `md-focus-ring` (interaction.css); any other outline is your own CSS";
|
||||
|
||||
expect($violations)->toBe([
|
||||
'tailwind/theme-colours.blade.php:1 '.$theme('bg-off-plan', 'off-plan'),
|
||||
'tailwind/theme-colours.blade.php:1 '.$theme('from-brand', 'brand'),
|
||||
'tailwind/theme-colours.blade.php:1 '.$theme('text-brand-ink', 'brand-ink'),
|
||||
'tailwind/theme-colours.blade.php:1 '.$theme('text-sport-run', 'sport-run'),
|
||||
'tailwind/theme-colours.blade.php:1 '.$theme('to-brand-end', 'brand-end'),
|
||||
'tailwind/theme-colours.blade.php:2 '.$theme('bg-route-reference/8', 'route-reference', $tint),
|
||||
'tailwind/theme-colours.blade.php:2 '.$theme('border-l-zone-4', 'zone-4'),
|
||||
'tailwind/theme-colours.blade.php:2 '.$theme('border-route-reference', 'route-reference'),
|
||||
'tailwind/theme-colours.blade.php:2 '.$theme('ring-offset-brand/[0.4]', 'brand', $tint),
|
||||
'tailwind/theme-colours.blade.php:3 Tailwind text utility `text-balance` compiles to nothing — write the rule in your own CSS',
|
||||
'tailwind/theme-colours.blade.php:3 Tailwind text utility `text-clip` compiles to nothing — write the rule in your own CSS',
|
||||
'tailwind/theme-colours.blade.php:3 Tailwind text utility `text-ellipsis` compiles to nothing — write the rule in your own CSS',
|
||||
'tailwind/theme-colours.blade.php:3 Tailwind text utility `text-pretty` compiles to nothing — write the rule in your own CSS',
|
||||
'tailwind/theme-colours.blade.php:3 Tailwind text utility `text-wrap` compiles to nothing — write the rule in your own CSS',
|
||||
"tailwind/theme-colours.blade.php:3 Tailwind's `text-nowrap` compiles to nothing — use `md-nowrap` (text.css)",
|
||||
"tailwind/theme-colours.blade.php:4 Tailwind border utility `border-dashed` compiles to nothing — {$line}",
|
||||
"tailwind/theme-colours.blade.php:4 Tailwind border utility `border-dotted` compiles to nothing — {$line}",
|
||||
"tailwind/theme-colours.blade.php:4 Tailwind border utility `border-none` compiles to nothing — {$line}",
|
||||
"tailwind/theme-colours.blade.php:4 Tailwind border utility `border-solid` compiles to nothing — {$line}",
|
||||
'tailwind/theme-colours.blade.php:4 Tailwind table utility `border-collapse` compiles to nothing — write the rule in your own CSS',
|
||||
'tailwind/theme-colours.blade.php:4 Tailwind table utility `border-separate` compiles to nothing — write the rule in your own CSS',
|
||||
'tailwind/theme-colours.blade.php:5 Tailwind gradient utility `from-0%` compiles to nothing — write the gradient in your own CSS',
|
||||
'tailwind/theme-colours.blade.php:5 Tailwind gradient utility `via-none` compiles to nothing — write the gradient in your own CSS',
|
||||
"tailwind/theme-colours.blade.php:5 Tailwind outline utility `outline-dashed` compiles to nothing — {$outline}",
|
||||
"tailwind/theme-colours.blade.php:5 Tailwind outline utility `outline-none` compiles to nothing — {$outline}",
|
||||
"tailwind/theme-colours.blade.php:5 Tailwind outline utility `ring-inset` compiles to nothing — {$outline}",
|
||||
'tailwind/theme-colours.blade.php:5 Tailwind shadow utility `shadow-none` compiles to nothing — use `var(--md-sys-elevation-*)` in your own CSS',
|
||||
'tailwind/theme-colours.blade.php:5 Tailwind text utility `decoration-wavy` compiles to nothing — write the rule in your own CSS',
|
||||
'tailwind/theme-colours.blade.php:6 Tailwind SVG utility `fill-none` compiles to nothing — write `fill` or `stroke` in your own CSS',
|
||||
'tailwind/theme-colours.blade.php:6 Tailwind background utility `bg-center` compiles to nothing — write the rule in your own CSS',
|
||||
'tailwind/theme-colours.blade.php:6 Tailwind background utility `bg-clip-text` compiles to nothing — write the rule in your own CSS',
|
||||
'tailwind/theme-colours.blade.php:6 Tailwind background utility `bg-cover` compiles to nothing — write the rule in your own CSS',
|
||||
'tailwind/theme-colours.blade.php:6 Tailwind background utility `bg-fixed` compiles to nothing — write the rule in your own CSS',
|
||||
'tailwind/theme-colours.blade.php:6 Tailwind background utility `bg-no-repeat` compiles to nothing — write the rule in your own CSS',
|
||||
'tailwind/theme-colours.blade.php:6 Tailwind background utility `bg-top-left` compiles to nothing — write the rule in your own CSS',
|
||||
'tailwind/theme-colours.blade.php:6 Tailwind colour utility `text-inherit` compiles to nothing — write `inherit` in your own CSS',
|
||||
'tailwind/theme-colours.blade.php:6 Tailwind interactivity utility `accent-auto` compiles to nothing — write the rule in your own CSS',
|
||||
'tailwind/theme-colours.blade.php:6 Tailwind text utility `text-shadow-sm` compiles to nothing — write the rule in your own CSS',
|
||||
"tailwind/theme-colours.blade.php:7 Tailwind border utility `border-bs-2` compiles to nothing — {$line}",
|
||||
'tailwind/theme-colours.blade.php:7 Tailwind palette colour `bg-mauve-500` compiles to nothing — M3 paints with roles: an `md-ink-*` class, or `var(--md-sys-color-*)` in your own CSS',
|
||||
]);
|
||||
});
|
||||
|
||||
it('reports an arbitrary [] value once, whatever utility it modifies, and strips a trailing !', function () {
|
||||
$violations = fixtureRelative(DesignGuard::scan(realpath(GUARD_FIXTURES.'/tailwind/arbitrary.blade.php'))->violations());
|
||||
|
||||
|
||||
Reference in New Issue
Block a user