diff --git a/resources/boost/skills/livewire-material-development/SKILL.md b/resources/boost/skills/livewire-material-development/SKILL.md index eac83fc2..b01c13e3 100644 --- a/resources/boost/skills/livewire-material-development/SKILL.md +++ b/resources/boost/skills/livewire-material-development/SKILL.md @@ -90,7 +90,7 @@ Scheme::resolveProfileUsing(fn (): ?string => Setting::get('color_profile')); ## Tokens -2.0.0's vocabulary is plain CSS, without Tailwind. `resources/css/foundation.css` is the one required import, first in the entry, followed by the stylesheets of the components the views render (see Setup; 1.x's `material.css` shortcut is gone). It declares the layer order `material.reset, material.tokens, material.base, material.layout, material.components, material.text, material.visibility`, so an application's unlayered CSS beats every package rule, and `hidden` or `x-cloak` hides any element. It brings the reset, the page's `surface` and `on-surface` in the brand typeface smoothed in grayscale (drop Tailwind's `antialiased`), every `--md-sys-*` token (spacing included: `--md-sys-measurement-space25` … `space900`, 2–72px), and `md-state-layer`, `md-focus-ring`, `md-touch-target`, `md-link`. Text on plain elements takes the fixed text classes of `resources/css/text.css` and nothing else: `md-type-{display|headline|title|body|label}-{lg|md|sm}` and `md-type-emphasized-…`; `md-ink` (on-surface), `md-ink-variant`, `md-ink-quiet`, `md-ink-primary`, `md-ink-error`, `md-ink-success`, `md-ink-warning`, `md-ink-info`, `md-ink-inverse`; `md-text-start|center|end`, `md-truncate`, `md-line-clamp-2|3`, `md-nowrap`, `md-tabular`, `md-visually-hidden`. Every component is plain CSS now; the Tailwind names below stay for the showcase and an application's own views, until Tailwind itself leaves the package. +2.0.0's vocabulary is plain CSS, without Tailwind. `resources/css/foundation.css` is the one required import, first in the entry, followed by the stylesheets of the components the views render (see Setup; 1.x's `material.css` shortcut is gone). It declares the layer order `material.reset, material.tokens, material.base, material.layout, material.components, material.text, material.visibility`, so an application's unlayered CSS beats every package rule, and `hidden` or `x-cloak` hides any element. It brings the reset, the page's `surface` and `on-surface` in the brand typeface smoothed in grayscale (drop Tailwind's `antialiased`), every `--md-sys-*` token (spacing included: `--md-sys-measurement-space25` … `space900`, 2–72px), and `md-state-layer`, `md-focus-ring`, `md-touch-target`, `md-link`. Text on plain elements takes the fixed text classes of `resources/css/text.css` and nothing else: `md-type-{display|headline|title|body|label}-{lg|md|sm}` and `md-type-emphasized-…`; `md-ink` (on-surface), `md-ink-variant`, `md-ink-quiet`, `md-ink-primary`, `md-ink-error`, `md-ink-success`, `md-ink-warning`, `md-ink-info`, `md-ink-inverse`; `md-text-start|center|end`, `md-truncate`, `md-line-clamp-2|3`, `md-nowrap`, `md-tabular`, `md-mono`, `md-visually-hidden`. Monospace is for a value read or typed character by character (a token, a recovery code, a file name, a key): put it in ``, `` or ``, which take `--md-ref-typeface-mono` already, or give another element `md-mono` after its `md-type-*` class; `` for a field. `--md-ref-typeface-mono` is the package's addition, the platform's monospace faces, not an M3 token. Every component is plain CSS now; the Tailwind names below stay for the showcase and an application's own views, until Tailwind itself leaves the package. Tailwind's default palette is cleared: every colour class names an M3 role. `text-red-600`, `bg-base-200` or `text-gray-500` compile to nothing. The rules behind the names below — which role, surface container, corner, type style, elevation level, motion spring, state and window size class to use, and M3's don'ts — are the `material-3` guideline (always on) and the `material-3-design` skill (the tables and Google's source pages); activate that skill before designing a screen. diff --git a/resources/css/components/field.css b/resources/css/components/field.css index c95ae66e..dda65079 100644 --- a/resources/css/components/field.css +++ b/resources/css/components/field.css @@ -123,7 +123,7 @@ } [data-md-field][data-md-mono] [data-md-field-control] { - font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace; + font-family: var(--md-ref-typeface-mono); } [data-md-field-control]::placeholder { diff --git a/resources/css/foundation/reset.css b/resources/css/foundation/reset.css index 815af0ab..3d11fe16 100644 --- a/resources/css/foundation/reset.css +++ b/resources/css/foundation/reset.css @@ -78,7 +78,7 @@ kbd, samp, pre { - font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace; + font-family: var(--md-ref-typeface-mono); font-feature-settings: normal; font-variation-settings: normal; font-size: 1em; diff --git a/resources/css/text.css b/resources/css/text.css index ce14f112..e324891e 100644 --- a/resources/css/text.css +++ b/resources/css/text.css @@ -42,6 +42,9 @@ * md-nowrap never wraps: a figure with its unit, a short label * md-tabular tabular figures, where digits change often (tables, clocks, * counters), so the layout does not shift + * md-mono the monospace typeface (`--md-ref-typeface-mono`), for a value read + * character by character outside ``; after an `md-type-*` class, + * whose `font` would otherwise set the brand face * md-visually-hidden read by assistive technology, not drawn: a label a picture already * gives the eye * @@ -309,6 +312,10 @@ font-variant-numeric: tabular-nums; } + .md-mono { + font-family: var(--md-ref-typeface-mono); + } + .md-visually-hidden { position: absolute; width: 1px; diff --git a/resources/css/tokens/type.css b/resources/css/tokens/type.css index f49b5f35..14517ad2 100644 --- a/resources/css/tokens/type.css +++ b/resources/css/tokens/type.css @@ -17,6 +17,12 @@ * heavier and fully rounded ("ROND" 100) — the axis that typeface exists for, verified by * `npm run check:font` — and they carry their own tracking, because M3 widens four of them and * takes Display Large's negative tracking back to zero. + * + * `--md-ref-typeface-mono` is the package's, not M3's (M3 names a brand and a plain typeface and + * nothing for code): the platform's own monospace faces, nothing downloaded, for what a person + * reads or types character by character — a token, a recovery code, a file or folder name, a key. + * ``, `` and `` take it from the reset, a `mono` field from field.css, any other + * element from `md-mono` (text.css). */ @layer material.reset, material.tokens, material.base, material.layout, material.components, material.text, material.visibility; @@ -25,6 +31,7 @@ :root { --md-ref-typeface-brand: 'Google Sans Flex', ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'; --md-ref-typeface-plain: var(--md-ref-typeface-brand); + --md-ref-typeface-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace; --md-ref-typeface-weight-regular: 400; --md-ref-typeface-weight-medium: 500; --md-ref-typeface-weight-bold: 700; diff --git a/src/Testing/DesignGuard.php b/src/Testing/DesignGuard.php index 3fe109ce..881ca8e3 100644 --- a/src/Testing/DesignGuard.php +++ b/src/Testing/DesignGuard.php @@ -161,9 +161,10 @@ class DesignGuard ['/^(?:cursor-[\w-]+|pointer-events-(?:none|auto)|select-(?:none|text|all|auto)|touch-[\w-]+|resize(?:-[xy]|-none)?|appearance-(?:none|auto)|scroll-(?:smooth|auto)|-?scroll-[mp][trblxyse]?-[\w.]+|snap-[\w-]+)$/', 'Tailwind interactivity utility `%s` compiles to nothing — write the rule in your own CSS'], ['/^(?:aspect-(?:auto|square|video|\d+\/\d+)|object-(?:contain|cover|fill|none|scale-down|top|bottom|center|left|right|left-top|left-bottom|right-top|right-bottom))$/', 'Tailwind media utility `%s` compiles to nothing — write `aspect-ratio`/`object-fit` in your own CSS'], ['/^font-(?:sans|serif)$/', 'Tailwind\'s `%s` compiles to nothing — the foundation already sets the brand typeface; any other `font-family` is your own CSS'], + ['/^font-mono$/', 'Tailwind\'s `%s` compiles to nothing — put the value in ``, `` or ``, or use `md-mono` (text.css)'], ['/^antialiased$/', 'Tailwind\'s `%s` compiles to nothing — the foundation already smooths text in grayscale (base.css); drop it'], ['/^(?:underline|no-underline)$/', 'Tailwind\'s `%s` compiles to nothing — `md-link` draws a link (interaction.css); any other decoration is your own CSS'], - ['/^(?:uppercase|lowercase|capitalize|normal-case|italic|not-italic|overline|line-through|underline-offset-\w+|decoration-(?:\d+|solid|double|dotted|dashed|wavy|auto|from-font|clone|slice)|font-mono|subpixel-antialiased|whitespace-(?:normal|pre|pre-line|pre-wrap|break-spaces)|break-(?:words|all|keep|normal)|wrap-(?:break-word|anywhere|normal)|text-(?:wrap|balance|pretty|ellipsis|clip|justify)|line-clamp-(?:\d+|none)|not-sr-only|list-(?:disc|decimal|none|inside|outside)|align-(?:baseline|top|middle|bottom|text-top|text-bottom|sub|super)|indent-[\w.]+|hyphens-(?:none|manual|auto)|(?:normal|lining|oldstyle|proportional)-nums|ordinal|slashed-zero|(?:diagonal|stacked)-fractions)$/', 'Tailwind text utility `%s` compiles to nothing — write the rule in your own CSS'], + ['/^(?:uppercase|lowercase|capitalize|normal-case|italic|not-italic|overline|line-through|underline-offset-\w+|decoration-(?:\d+|solid|double|dotted|dashed|wavy|auto|from-font|clone|slice)|subpixel-antialiased|whitespace-(?:normal|pre|pre-line|pre-wrap|break-spaces)|break-(?:words|all|keep|normal)|wrap-(?:break-word|anywhere|normal)|text-(?:wrap|balance|pretty|ellipsis|clip|justify)|line-clamp-(?:\d+|none)|not-sr-only|list-(?:disc|decimal|none|inside|outside)|align-(?:baseline|top|middle|bottom|text-top|text-bottom|sub|super)|indent-[\w.]+|hyphens-(?:none|manual|auto)|(?:normal|lining|oldstyle|proportional)-nums|ordinal|slashed-zero|(?:diagonal|stacked)-fractions)$/', 'Tailwind text utility `%s` compiles to nothing — write the rule in your own CSS'], ['/^bg-(?:(?:gradient-to|linear-to)-[a-z]+|radial|conic|cover|contain|auto|center|top|bottom|left|right|no-repeat|repeat(?:-[xy])?|fixed|local|scroll|none|clip-[a-z]+|origin-[a-z]+)$/', 'Tailwind background utility `%s` compiles to nothing — write the rule in your own CSS'], ]; diff --git a/tests/Feature/DesignGuardTest.php b/tests/Feature/DesignGuardTest.php index 39cd7f49..ebad9df2 100644 --- a/tests/Feature/DesignGuardTest.php +++ b/tests/Feature/DesignGuardTest.php @@ -369,10 +369,10 @@ it('reports position, border, effect, interactivity and text utilities with the 'tailwind/utilities.blade.php:3 Tailwind display utility `table` compiles to nothing — write the `display` rule in your own CSS', 'tailwind/utilities.blade.php:3 Tailwind media utility `aspect-video` compiles to nothing — write `aspect-ratio`/`object-fit` in your own CSS', 'tailwind/utilities.blade.php:3 Tailwind media utility `object-cover` compiles to nothing — write `aspect-ratio`/`object-fit` in your own CSS', - 'tailwind/utilities.blade.php:3 Tailwind text utility `font-mono` compiles to nothing — write the rule in your own CSS', 'tailwind/utilities.blade.php:3 Tailwind text utility `list-disc` compiles to nothing — write the rule in your own CSS', 'tailwind/utilities.blade.php:3 Tailwind text utility `uppercase` compiles to nothing — write the rule in your own CSS', "tailwind/utilities.blade.php:3 Tailwind's `antialiased` compiles to nothing — the foundation already smooths text in grayscale (base.css); drop it", + "tailwind/utilities.blade.php:3 Tailwind's `font-mono` compiles to nothing — put the value in ``, `` or ``, or use `md-mono` (text.css)", "tailwind/utilities.blade.php:3 Tailwind's `font-sans` compiles to nothing — the foundation already sets the brand typeface; any other `font-family` is your own CSS", "tailwind/utilities.blade.php:3 Tailwind's `text-end` compiles to nothing — use `md-text-end` (text.css)", "tailwind/utilities.blade.php:3 Tailwind's `underline` compiles to nothing — `md-link` draws a link (interaction.css); any other decoration is your own CSS", diff --git a/tests/Feature/StylesheetsTest.php b/tests/Feature/StylesheetsTest.php index 3126f740..67868adc 100644 --- a/tests/Feature/StylesheetsTest.php +++ b/tests/Feature/StylesheetsTest.php @@ -222,6 +222,19 @@ it('paints the page in surface and on-surface, in the brand typeface, smoothed i ->not->toContain('font-smoothing'); }); +it('names the monospace faces once, as a typeface token the reset, the field and md-mono read', function () { + // Not an M3 token: M3 names a brand and a plain typeface and nothing for code. + $sources = collect(File::allFiles(stylesheetPath())) + ->filter(fn (SplFileInfo $file): bool => str_contains($file->getContents(), 'ui-monospace')) + ->map(fn (SplFileInfo $file): string => str_replace(stylesheetPath().'/', '', $file->getPathname())) + ->values() + ->all(); + + expect($sources)->toBe(['tokens/type.css']) + ->and((string) file_get_contents(stylesheetPath('foundation/reset.css')))->toContain('font-family: var(--md-ref-typeface-mono);') + ->and((string) file_get_contents(stylesheetPath('components/field.css')))->toContain('font-family: var(--md-ref-typeface-mono);'); +}); + it('leaves no stylesheet under resources/css/ outside all.css or showcase.css', function () { // The full tree now that Tailwind is gone (plan step 39): every .css file on disk, not just the // ones a bundler happens to reach — a stray or orphaned file would show up here even though @@ -710,6 +723,7 @@ it('ships exactly the documented text classes, each ink an M3 role', function () 'md-line-clamp-3' => ['overflow' => 'hidden', 'display' => '-webkit-box', '-webkit-box-orient' => 'vertical', '-webkit-line-clamp' => '3'], 'md-nowrap' => ['white-space' => 'nowrap'], 'md-tabular' => ['font-variant-numeric' => 'tabular-nums'], + 'md-mono' => ['font-family' => 'var(--md-ref-typeface-mono)'], 'md-visually-hidden' => [ 'position' => 'absolute', 'width' => '1px', 'height' => '1px', 'padding' => '0', 'margin' => '-1px', 'overflow' => 'hidden', 'clip-path' => 'inset(50%)', 'white-space' => 'nowrap', 'border-width' => '0',