Package views now write <x-livewire-material::button>, so a configured prefix (which Blade spells <x-m::button>) and an application component of the same name can no longer break or shadow them. The showcase rewrites its examples to the configured prefix. Adds the README, and waits for the adaptive rail to hear a resize before the navigation tests press its menu button. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01V9NnLxnPp8vaaurb3Z1MFy
165 lines
6.2 KiB
Markdown
165 lines
6.2 KiB
Markdown
# Livewire Material
|
|
|
|
Material 3 Expressive components for Laravel and Livewire, built on Tailwind CSS 4.
|
|
|
|
- Anonymous Blade components for the current M3 Expressive catalogue: buttons and FABs, menus, chips, text fields, selection controls, sliders, pickers, dialogs and sheets, lists, cards, carousels, progress and loading indicators, snackbars, tabs, app bars, toolbars, navigation bars and rails, an adaptive app shell, data tables and pagination.
|
|
- A colour scheme generated from one seed colour with Google's colour science (`php artisan material:scheme`), light and dark, and a theme that is chosen before the first paint.
|
|
- The full Material Symbols Rounded set and the M3 Expressive shapes, drawn inline without an icon package.
|
|
- Error pages and a Markdown mail theme in the same scheme.
|
|
- A showcase of every component in the application's own scheme, a design guard for tests, and Laravel Boost guidelines and a skill for AI agents.
|
|
|
|
No JavaScript libraries beyond the Alpine that ships with Livewire. Browsers: Chrome 125+, Firefox 147+, Safari 18.4+.
|
|
|
|
## Requirements
|
|
|
|
PHP 8.4+, Laravel 13, Livewire 4, Tailwind CSS 4 with Vite, and Node (for `material:scheme`).
|
|
|
|
## Installation
|
|
|
|
The package is served from Gitea. Add the repository and require it:
|
|
|
|
```bash
|
|
composer config repositories.livewire-material vcs https://gitea.nonameweb.ch/noNameWEB/livewire-material.git
|
|
composer require nonameweb/livewire-material
|
|
```
|
|
|
|
### Stylesheet and script
|
|
|
|
The application's build imports from `vendor/`, so Composer packages must be installed before `npm run build` — in a Dockerfile, copy `composer.json`, run `composer install`, then build the assets.
|
|
|
|
```css
|
|
/* resources/css/app.css */
|
|
@import 'tailwindcss';
|
|
@import '../../vendor/nonameweb/livewire-material/resources/css/material.css';
|
|
@import './material-scheme.css';
|
|
|
|
@source '../../vendor/nonameweb/livewire-material/resources/views';
|
|
@source '../../vendor/nonameweb/livewire-material/src';
|
|
```
|
|
|
|
```js
|
|
// resources/js/app.js
|
|
import '../../vendor/nonameweb/livewire-material/resources/js/material.js'
|
|
```
|
|
|
|
Do not install Alpine separately; Livewire provides it.
|
|
|
|
### Layout
|
|
|
|
The theme script goes in `<head>`, before `@vite`, so the page paints in the visitor's theme:
|
|
|
|
```blade
|
|
<!DOCTYPE html>
|
|
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
|
|
<head>
|
|
<meta charset="utf-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
<x-theme-script />
|
|
@vite(['resources/css/app.css', 'resources/js/app.js'])
|
|
</head>
|
|
<body class="bg-surface font-sans text-on-surface antialiased">
|
|
{{ $slot }}
|
|
<x-toast />
|
|
</body>
|
|
</html>
|
|
```
|
|
|
|
### Colour scheme
|
|
|
|
Generate the scheme from a seed colour. It writes `resources/css/material-scheme.css` (imported above) and `material-scheme.json` (read by the mail theme):
|
|
|
|
```bash
|
|
php artisan material:scheme "#4f46e5" --variant=tonal-spot
|
|
```
|
|
|
|
Variants: `tonal-spot`, `vibrant`, `expressive`, `neutral`, `fidelity`, `content`, `monochrome`, `rainbow`, `fruit-salad`. `--contrast` runs from -1 to 1; `--success`, `--warning` and `--info` seed the state colours. Regenerate instead of editing the file.
|
|
|
|
### Configuration
|
|
|
|
```bash
|
|
php artisan vendor:publish --tag=livewire-material-config
|
|
```
|
|
|
|
- `prefix` — components are `<x-button>`, `<x-card>`… Set `'m'` when a name clashes with the application's own components, and they become `<x-m::button>`. `<x-livewire-material::button>` always works.
|
|
- `theme.default` (`light`, `dark` or `system`), `theme.storage_key`, `theme.legacy_keys` (an earlier toggle's localStorage keys, adopted once).
|
|
- `fields.variant` — text fields `outlined` (default) or `filled`.
|
|
- `pagination` — draw Laravel's and Livewire's paginators in M3 (default `true`).
|
|
- `showcase.enabled`, `showcase.path`, `showcase.middleware`, `showcase.vite`.
|
|
- `node` — the Node binary for `material:scheme`.
|
|
|
|
## Usage
|
|
|
|
```blade
|
|
<x-card title="holiday-photos.zip" subtitle="248 MB · expires in 3 days" variant="outlined">
|
|
<x-slot:actions>
|
|
<x-button label="Copy link" icon="content_copy" wire:click="copy" />
|
|
<x-button label="Delete" danger wire:click="$set('confirming', true)" />
|
|
</x-slot:actions>
|
|
</x-card>
|
|
|
|
<x-modal wire:model="confirming" title="Delete this share?" icon="delete">
|
|
Recipients lose access at once.
|
|
<x-slot:actions>
|
|
<x-button label="Cancel" x-on:click="close()" />
|
|
<x-button label="Delete" danger wire:click="delete" />
|
|
</x-slot:actions>
|
|
</x-modal>
|
|
```
|
|
|
|
```php
|
|
use NoNameWeb\LivewireMaterial\Concerns\Toasts;
|
|
|
|
class Shares extends Component
|
|
{
|
|
use Toasts;
|
|
|
|
public function copy(): void
|
|
{
|
|
$this->success('Link copied');
|
|
}
|
|
}
|
|
```
|
|
|
|
Every component, prop and slot is documented in the Boost skill (`resources/boost/skills/livewire-material-development/SKILL.md`) and shown in the showcase.
|
|
|
|
## Showcase
|
|
|
|
While the application runs locally (or with `MATERIAL_SHOWCASE=true`), `/material` renders every token and component, in every variant, in the application's own scheme and theme.
|
|
|
|
## Testing the design
|
|
|
|
```php
|
|
use NoNameWeb\LivewireMaterial\Testing\DesignGuard;
|
|
|
|
it('uses only what compiles', function () {
|
|
expect(DesignGuard::scan([resource_path('views'), resource_path('js'), app_path()])
|
|
->forbidColours(['tertiary'])
|
|
->violations())->toBe([]);
|
|
});
|
|
```
|
|
|
|
The guard fails on maryUI tags, daisyUI classes, colours the theme does not declare, unknown Material Symbol names and Blade directives written inside component tags.
|
|
|
|
## AI agents
|
|
|
|
With [Laravel Boost](https://github.com/laravel/boost), `php artisan boost:install` (or `boost:update --discover`) picks up the package's guideline and the `livewire-material-development` skill.
|
|
|
|
## Developing the package
|
|
|
|
```bash
|
|
composer install && npm install
|
|
npm run build # the Workbench's assets (or `npm run dev` while working)
|
|
composer serve # the showcase at http://127.0.0.1:8000/material
|
|
vendor/bin/pest --testsuite=Feature
|
|
npx playwright install
|
|
vendor/bin/pest --testsuite=Browser --browser chrome # also firefox, safari
|
|
```
|
|
|
|
## Credits
|
|
|
|
Material Symbols, the M3 Expressive shapes, Google Sans Flex, material-color-utilities and Jetpack Compose Material 3's tokens and algorithms are Google's and the Android Open Source Project's; see `NOTICE`.
|
|
|
|
## License
|
|
|
|
MIT. See `LICENSE`.
|