diff --git a/README.md b/README.md
new file mode 100644
index 00000000..5c8d4783
--- /dev/null
+++ b/README.md
@@ -0,0 +1,164 @@
+# 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 `
`, before `@vite`, so the page paints in the visitor's theme:
+
+```blade
+
+
+
+
+
+
+ @vite(['resources/css/app.css', 'resources/js/app.js'])
+
+
+ {{ $slot }}
+
+
+
+```
+
+### 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 ``, ``… Set `'m'` when a name clashes with the application's own components, and they become ``. `` 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
+
+
+
+
+
+
+
+
+ Recipients lose access at once.
+
+
+
+
+
+```
+
+```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`.
diff --git a/config/livewire-material.php b/config/livewire-material.php
index a1fb8244..fb9fb7a5 100644
--- a/config/livewire-material.php
+++ b/config/livewire-material.php
@@ -8,8 +8,10 @@ return [
|--------------------------------------------------------------------------
|
| Every component is an anonymous Blade component. Without a prefix they are
- | , and so on; set a prefix such as 'm-' when a name
- | clashes with one of the application's own components ().
+ | , and so on; set a prefix such as 'm' when a name
+ | clashes with one of the application's own components, and they become
+ | , . They are always
+ | as well.
|
*/
diff --git a/resources/boost/skills/livewire-material-development/SKILL.md b/resources/boost/skills/livewire-material-development/SKILL.md
index 8cdccc5c..ad91e0de 100644
--- a/resources/boost/skills/livewire-material-development/SKILL.md
+++ b/resources/boost/skills/livewire-material-development/SKILL.md
@@ -764,7 +764,7 @@ It fails on maryUI tags, daisyUI classes, colours the theme does not declare, un
## Conventions
-- Components are anonymous Blade components: `` without a prefix, or `` when `config('livewire-material.prefix')` is set.
+- Components are anonymous Blade components: `` without a prefix, or `` when `config('livewire-material.prefix')` is set; `` always works.
- Write class names out whole. Tailwind cannot compile `'text-'.$tone` or `type-{{ $size }}`, and the design guard cannot read them.
- The showcase at `/material` (local only, `MATERIAL_SHOWCASE=true` to force it) renders every token and component.
diff --git a/resources/views/components/account-menu.blade.php b/resources/views/components/account-menu.blade.php
index f8a31661..b5417baf 100644
--- a/resources/views/components/account-menu.blade.php
+++ b/resources/views/components/account-menu.blade.php
@@ -32,7 +32,7 @@
$initials = $image ? null : ($avatar ?? \Illuminate\Support\Str::of((string) $name)->explode(' ')->filter()->take(2)->map(fn (string $word): string => mb_strtoupper(mb_substr($word, 0, 1)))->join(''));
@endphp
-
+
+
@endif
@@ -60,20 +60,20 @@
@endif
-
+
@endif
{{ $slot }}
@if ($theme)
-
+ {{ __('Theme') }}
-
+
@endif
@isset($footer)
-
+
{{ $footer }}
@endisset
-
+
diff --git a/resources/views/components/alert.blade.php b/resources/views/components/alert.blade.php
index fd234346..dc177cb0 100644
--- a/resources/views/components/alert.blade.php
+++ b/resources/views/components/alert.blade.php
@@ -40,7 +40,7 @@
{{ $attributes->class(['flex items-start gap-3 rounded-corner-md p-4', $colours]) }}
>
@if ($icon)
-
+
@endif
diff --git a/resources/views/showcase/components/example.blade.php b/resources/views/showcase/components/example.blade.php
index ed189269..6d9d9e9d 100644
--- a/resources/views/showcase/components/example.blade.php
+++ b/resources/views/showcase/components/example.blade.php
@@ -3,6 +3,21 @@
@props(['title' => null, 'code', 'stack' => false])
+@php
+ // Written as an application without a prefix writes it; under a configured prefix the tags are
+ // rewritten to it, so what renders and what is shown is what this application would write.
+ $prefix = config('livewire-material.prefix');
+
+ if (filled($prefix)) {
+ $names = collect(glob(\NoNameWeb\LivewireMaterial\LivewireMaterialServiceProvider::componentPath().'/*.blade.php'))
+ ->map(fn (string $path): string => preg_quote(basename($path, '.blade.php'), '/'))
+ ->sortByDesc(fn (string $name): int => strlen($name))
+ ->implode('|');
+
+ $code = preg_replace('/<(\/?)x-('.$names.')(?=[\s\/>])/', '<$1x-'.$prefix.'::$2', $code);
+ }
+@endphp
+
@if ($title)
{{ $title }}
diff --git a/resources/views/showcase/layout.blade.php b/resources/views/showcase/layout.blade.php
index eff1578d..93e73bd7 100644
--- a/resources/views/showcase/layout.blade.php
+++ b/resources/views/showcase/layout.blade.php
@@ -7,7 +7,7 @@
@yield('title', 'Livewire Material')
-
+
@vite(config('livewire-material.showcase.vite'))
@livewireStyles
@@ -40,7 +40,7 @@
@yield('content')
-
+
@livewireScripts
diff --git a/resources/views/showcase/sections/buttons.blade.php b/resources/views/showcase/sections/buttons.blade.php
index 840a2cdc..6cbaf1af 100644
--- a/resources/views/showcase/sections/buttons.blade.php
+++ b/resources/views/showcase/sections/buttons.blade.php
@@ -76,7 +76,7 @@
BLADE,
- 'A choice as a connected group ()' => <<<'BLADE'
+ 'A choice as a connected group' => <<<'BLADE'