Files
livewire-material/resources/css/showcase.css
T
Andreas Reinhold / reiniandClaude Opus 5 fb7007c976
tests / feature (8.4) (push) Successful in 2m0s
tests / feature (8.5) (push) Successful in 2m0s
tests / browser (chrome, chromium) (push) Failing after 8m3s
tests / browser (firefox, firefox) (push) Failing after 12m58s
tests / browser (safari, webkit) (push) Failing after 13m8s
Take Tailwind out of the package, and its detection out of the guard
Tailwind left the stack in 2.0.0, but the package still carried about 330
mentions of it. What the guard's Tailwind detection protected — a class
that compiles to nothing — is now protected by a check that does not care
where a dead class came from.

DesignGuard: about 500 lines of Tailwind tables, scales, palettes and
"2.0.0 replacement" hints give way to one check — a class a view or PHP
file writes that neither the application's stylesheets nor the package's
own declare. It catches a utility of any framework, a typo and a class
whose rules were deleted alike, so it also found two classes ReStride
draws nothing with. A stylesheet has to be in reach for it: the `.css`
files among the scanned paths, or what the `missingStylesheets()` entry
imports. The class reader no longer mistakes an array index for a class
list (`$block['base']`), and it reads the array a class helper is given,
where it read nothing before.

The package's own three Tailwind self-guards go with it. Only their one
unique check stays, as a test of its own: every `matchMedia` width in
resources/js is an M3 breakpoint.

The pagination views are `material.blade.php` and
`simple-material.blade.php`; only Laravel's and Livewire's default theme
names ever made them `tailwind`. The provider sets `Paginator`'s default
views and switches `livewire.pagination_theme` to `material` when it is
still Livewire's own default, so no application can forget the config; a
theme an application chose, and a component's own `$paginationTheme` or
`paginationView()`, still win.

The rest is prose: the layer-order guidance for an application that still
builds Tailwind, the Tailwind wording in the README, the Boost guidelines
and the development skill, and about 25 "this used to be a Tailwind
utility" comments, along with every "plan step NN" pointer into a
gitignored folder. The reset keeps its credit, and NOTICE now carries it
too.

Feature suite 1159 passed, Chrome browser suite 299 passed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-17 21:07:39 +02:00

285 lines
12 KiB
CSS

/*
* The showcase's own chrome: what its pages draw beyond the layout components, the `md-*` text
* classes and the shared interaction classes — the rail's wordmark, the search box and its
* results, a keyboard key in running text, an example's card and its code sample, and the
* foundation pages' specimens: a colour swatch, a type-scale row, a corner swatch, an elevation
* tile, a motion track and its dot, an icon search result and the Layout page's breakpoint cards.
*
* Only the showcase's own pages use it. The examples do not: an example's code is what an
* application copies, so it writes only what an application has — the components and their props,
* the layout components, the text classes, and an inline `style` from the `--md-sys-*` tokens where
* a demo needs a size, a frame or a colour of its own.
*
* In `material.components`: the showcase is one more page drawn over the foundation and the layout
* components, where `components/error-page.css` sits for the same reason, and an application's
* unlayered CSS still outranks it. Keyed on `data-md-showcase-*` hooks, never a bare element
* selector, since `ShowcaseAssetController` bundles this file with `all.css` and it must restyle
* nothing outside those hooks. It imports nothing: every token and layout rule it builds on is in
* `all.css`, ahead of it in the bundle. Values are tokens, apart from a specimen's own size; its
* media queries are M3's breakpoints, in px.
*
* Two kinds of rule sit outside the layers on purpose, as an application's own classes would:
* `.showcase-w-narrow` proves the point its example makes (Text fields, "Narrower": an unlayered
* rule from the call site beats the package's layered default, which an inline `style` would win
* regardless of layers, proving nothing), and `.showcase-ink-*` are the colours the Menus example
* passes to `icon-class`, the application's own class that prop takes.
*/
@layer material.reset, material.tokens, material.base, material.layout, material.components, material.text, material.visibility;
@layer material.components {
/* The rail's wordmark: `md-type-title-lg md-truncate md-focus-ring` cover the type, the
ellipsis and the ring; `display: block` gives the truncated text a width to ellipsize
within, and the corner rounds the ring to match the state layer every other rail control
draws (foundation/interaction.css's `md-focus-ring` takes its shape from the element). */
[data-md-showcase-brand] {
display: block;
border-radius: var(--md-sys-shape-corner-xs);
}
/* The search bar fills the app bar's search slot. */
[data-md-showcase-search] {
width: 100%;
}
[data-md-showcase-search-hint] {
padding: var(--md-sys-measurement-space125) var(--md-sys-measurement-space200);
}
/* A kbd in running text: the search hint's "/", and the intro paragraph's own. */
[data-md-showcase-kbd] {
display: inline-block;
border-radius: var(--md-sys-shape-corner-xs);
background-color: var(--md-sys-color-surface-container-highest);
padding: 0 var(--md-sys-measurement-space75);
}
/* One search result: title over kind and context, centred in a 56px row (space700, M3's list
row) the way a menu item is. */
[data-md-showcase-search-result] {
display: flex;
flex-direction: column;
justify-content: center;
min-height: var(--md-sys-measurement-space700);
padding: var(--md-sys-measurement-space100) var(--md-sys-measurement-space200);
}
/* The bottom breathing room under a showcase page's content, inside the pane's own margins. */
[data-md-showcase-page] {
padding-block-end: var(--md-sys-measurement-space600);
}
/* Each section's group of components on the overview: a tonal box behind its icon, the way a
list's leading icon sits in a container (M3's small tonal container). */
[data-md-showcase-section-icon] {
display: grid;
place-items: center;
width: var(--md-sys-measurement-space600);
height: var(--md-sys-measurement-space600);
border-radius: var(--md-sys-shape-corner-lg);
background-color: var(--md-sys-color-secondary-container);
color: var(--md-sys-color-on-secondary-container);
}
/* An example: scroll-margin so a hash link (the search result, the "next section" nav) lands
clear of the sticky app bar above it. */
[data-md-showcase-example] {
scroll-margin-top: var(--md-sys-measurement-space900);
}
[data-md-showcase-code-summary] {
display: inline-block;
cursor: pointer;
border-radius: var(--md-sys-shape-corner-xs);
}
[data-md-showcase-code] {
margin-top: var(--md-sys-measurement-space100);
overflow-x: auto;
border-radius: var(--md-sys-shape-corner-sm);
background-color: var(--md-sys-color-surface-container-highest);
padding: var(--md-sys-measurement-space125);
}
/* Colour: a role swatch. Its fill is the one declaration that has to be the caller's inline
`style` (the role it shows decides it), so this rule only gives it a size and an edge; `lg`
is the big per-theme grid's, the plain attribute the smaller contrast-level list's. */
[data-md-showcase-swatch] {
display: block;
flex-shrink: 0;
width: var(--md-sys-measurement-space300);
height: var(--md-sys-measurement-space300);
border-radius: var(--md-sys-shape-corner-xs);
border: 1px solid var(--md-sys-color-outline-variant);
}
[data-md-showcase-swatch][data-md-showcase-size='lg'] {
width: var(--md-sys-measurement-space400);
height: var(--md-sys-measurement-space400);
}
/* Lets the role name beside a swatch ellipsize inside its row instead of widening the grid. */
[data-md-showcase-swatch-label] {
min-width: 0;
}
/* Type: one typescale style beside its label and its emphasized twin, a row of the surface
they share. A single column below `expanded` (840px), where the label, the regular sample
and the emphasized one no longer fit a line each. */
[data-md-showcase-type-row] {
display: grid;
gap: var(--md-sys-measurement-space100);
padding: var(--md-sys-measurement-space200);
}
[data-md-showcase-type-row] + [data-md-showcase-type-row] {
border-top: 1px solid var(--md-sys-color-outline-variant);
}
@media (width >= 840px) {
[data-md-showcase-type-row] {
grid-template-columns: 192px 1fr 1fr;
align-items: baseline;
}
}
/* Shape: a corner swatch, filled with a tonal colour that is decoration only (never meaning,
same as the corner it demonstrates), one per corner token. The swatch is a `<x-surface>`
hook (`data-md-surface`, layout/surface.css) for its `data-md-corner` table alone — this
rule's own background outranks surface.css's, `material.components` over `material.layout`
whatever either's specificity, so the swatch keeps its tonal fill rather than surface.css's
default surface-container. */
[data-md-showcase-shape-swatch] {
display: block;
height: 80px;
background-color: var(--md-sys-color-primary-container);
}
/* Elevation: a tile at one shadow level, on the surface-container-high M3 pairs a shadow with. */
[data-md-showcase-elevation-tile] {
display: flex;
align-items: center;
justify-content: center;
height: 96px;
border-radius: var(--md-sys-shape-corner-md);
background-color: var(--md-sys-color-surface-container-high);
}
[data-md-showcase-elevation-tile][data-md-elevation='1'] {
box-shadow: var(--md-sys-elevation-1);
}
[data-md-showcase-elevation-tile][data-md-elevation='2'] {
box-shadow: var(--md-sys-elevation-2);
}
[data-md-showcase-elevation-tile][data-md-elevation='3'] {
box-shadow: var(--md-sys-elevation-3);
}
[data-md-showcase-elevation-tile][data-md-elevation='4'] {
box-shadow: var(--md-sys-elevation-4);
}
[data-md-showcase-elevation-tile][data-md-elevation='5'] {
box-shadow: var(--md-sys-elevation-5);
}
/* Motion: one spring's row (its name, and a track the dot travels), and the dot itself — its
colour is decoration, its size is the only thing this file fixes; the transition is the
spring under test, so it stays the view's own inline style. */
[data-md-showcase-motion-row] {
display: grid;
grid-template-columns: 144px 1fr;
align-items: center;
gap: var(--md-sys-measurement-space200);
}
[data-md-showcase-motion-track] {
height: var(--md-sys-measurement-space400);
}
[data-md-showcase-motion-dot] {
width: var(--md-sys-measurement-space400);
height: var(--md-sys-measurement-space400);
border-radius: var(--md-sys-shape-corner-full);
background-color: var(--md-sys-color-tertiary);
}
/* Icons: one search result's mask (its `mask` shorthand is the fetched symbol, so it stays the
view's own x-bind:style), 24px by default and 20px once optical size 20 is on — the state a
script toggles as data-md-showcase-icon-size, never a class. */
[data-md-showcase-icon-mask] {
display: block;
width: 24px;
height: 24px;
background-color: currentColor;
}
[data-md-showcase-icon-mask][data-md-showcase-icon-size='20'] {
width: 20px;
height: 20px;
}
/* Layout: the five breakpoint cards, each lit by the same range query the layout components'
own stylesheets use, so the page proves the breakpoints rather than only describing them. */
[data-md-showcase-breakpoint-card] {
border-radius: var(--md-sys-shape-corner-md);
background-color: var(--md-sys-color-surface-container);
padding: var(--md-sys-measurement-space200);
}
@media (width < 600px) {
[data-md-showcase-breakpoint-card='compact'] {
background-color: var(--md-sys-color-primary-container);
color: var(--md-sys-color-on-primary-container);
}
}
@media (600px <= width < 840px) {
[data-md-showcase-breakpoint-card='medium'] {
background-color: var(--md-sys-color-primary-container);
color: var(--md-sys-color-on-primary-container);
}
}
@media (840px <= width < 1200px) {
[data-md-showcase-breakpoint-card='expanded'] {
background-color: var(--md-sys-color-primary-container);
color: var(--md-sys-color-on-primary-container);
}
}
@media (1200px <= width < 1600px) {
[data-md-showcase-breakpoint-card='large'] {
background-color: var(--md-sys-color-primary-container);
color: var(--md-sys-color-on-primary-container);
}
}
@media (width >= 1600px) {
[data-md-showcase-breakpoint-card='extra-large'] {
background-color: var(--md-sys-color-primary-container);
color: var(--md-sys-color-on-primary-container);
}
}
}
/* Deliberately unlayered, to make the point fields.blade.php's hint names: an application's own
rule beats the package's layered default even though both set the same property. An inline
`style` would win regardless of layers, which would not demonstrate that. */
.showcase-w-narrow {
max-width: 320px;
}
/* An application's own icon colours, for menus.blade.php's `icon-class` example: unlayered, as the
menu item's header says a caller's class is, so it paints the icon over the item's ink (and a
disabled item's icon still stays disabled). */
.showcase-ink-tertiary {
color: var(--md-sys-color-tertiary);
}
.showcase-ink-secondary {
color: var(--md-sys-color-secondary);
}