Scaffold the Livewire Material package
tests / lint (push) Successful in 1m14s
tests / feature (8.4) (push) Successful in 56s
tests / feature (8.5) (push) Successful in 56s
tests / browser (chrome, chromium) (push) Successful in 2m9s
tests / browser (firefox, firefox) (push) Successful in 1m34s
tests / browser (safari, webkit) (push) Successful in 1m41s

The skeleton for nonameweb/livewire-material: service provider and config
(unprefixed components, blade-icons' own <x-icon> switched off, an opt-in
showcase at /material), the Testbench Workbench with its Vite build, the
CSS and JS entry points applications import, the Boost guideline and skill
with a drift test, and Gitea CI running Pint, feature tests on PHP 8.4 and
8.5, and browser tests in Chrome, Firefox and Safari.

The plan moved here from SealShare: docs/plans/livewire-material.md.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V9NnLxnPp8vaaurb3Z1MFy
This commit is contained in:
Andreas Reinhold / reini
2026-09-13 04:59:21 +02:00
co-authored by Claude Opus 5
commit 9b53891a8e
33 changed files with 2731 additions and 0 deletions
@@ -0,0 +1,9 @@
@verbatim
## Livewire Material
This application uses `nonameweb/livewire-material`: Material 3 Expressive components for Laravel and Livewire, built on Tailwind CSS. It replaces UI kits such as maryUI, daisyUI and Flux in this application.
- Components are anonymous Blade components, unprefixed unless `config/livewire-material.php` sets a `prefix`. Before writing or changing a view that uses them, activate the `livewire-material-development` skill for the props, slots and traps of each component.
- Never write maryUI tags (`<x-mary-*>`) or daisyUI classes (`btn`, `card`, `badge`, `bg-base-200`, `text-base-content`). They compile to nothing and fail silently.
- While the application runs locally, every component renders in the application's own scheme at `/material` (the showcase).
@endverbatim
@@ -0,0 +1,45 @@
---
name: livewire-material-development
description: Build Laravel and Livewire views with Livewire Material's Material 3 Expressive Blade components — props, slots, theming and the Livewire traps each component handles.
---
# Livewire Material Development
## When to use this skill
Use this skill when writing or changing any Blade view, Livewire component view or layout in an application that requires `nonameweb/livewire-material`, and when styling, theming or testing such views.
## Setup
The package ships CSS and JavaScript that the application imports from `vendor/`, after Tailwind:
```css
/* resources/css/app.css */
@import 'tailwindcss';
@import '../../vendor/nonameweb/livewire-material/resources/css/material.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'
```
Composer packages must be installed before the Vite build (in Dockerfiles and CI alike), or these imports have nothing to read.
## Conventions
- Components are anonymous Blade components: `<x-name>` without a prefix, or `<x-{prefix}name>` when `config('livewire-material.prefix')` is set.
- The showcase at `/material` (local only, `MATERIAL_SHOWCASE` to force it) renders every component with its Blade snippet.
## Components
Each component the package ships is listed here with its props and slots.
## Livewire traps
- Blade directives do not compile inside a component tag's attributes: `<x-foo x-show="ok(@js($value))">` reaches the browser as literal text. On a component tag use `{{ }}` and `:prop` bindings, or put the Alpine on a plain element inside the slot.
- Never pass `hidden`, a display utility or a position (`absolute`, `relative`) to a component: it is merged beside the component's own and whichever Tailwind emits last wins. Wrap the component in an element that carries it. A variant that only hides (`max-sm:hidden`) is safe.
- `$attributes->wire('model')->value()` is `false`, not `null`, when there is no `wire:model`, and `filled(false)` is true. Normalise with `?: null`.
- End every statement in a multi-line Alpine attribute with `;`: an inline `@if … @endif` inside it swallows the newline after it.
+10
View File
@@ -0,0 +1,10 @@
/*
* Livewire Material — the one stylesheet an application imports, after Tailwind:
*
* @import 'tailwindcss';
* @import '../../vendor/nonameweb/livewire-material/resources/css/material.css';
* @source '../../vendor/nonameweb/livewire-material/resources/views';
* @source '../../vendor/nonameweb/livewire-material/src';
*
* Colour roles, shape, type, motion, elevation and the component styles arrive in 0.2.0.
*/
+8
View File
@@ -0,0 +1,8 @@
/*
* Livewire Material — imported once from the application's app.js:
*
* import '../../vendor/nonameweb/livewire-material/resources/js/material.js'
*
* Alpine ships with Livewire, so this only registers onto it: the theme store, the
* snackbar listener and the list-row behaviour arrive in 0.2.0.
*/
View File
+12
View File
@@ -0,0 +1,12 @@
@extends('livewire-material::showcase.layout')
@section('content')
<main class="mx-auto max-w-5xl px-4 py-10">
<h1 class="text-3xl">Livewire Material</h1>
<p class="mt-2">
Every component, in every variant, colour, size and state, in this application's own scheme.
Sections appear here as the components land.
</p>
</main>
@endsection
+18
View File
@@ -0,0 +1,18 @@
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="robots" content="noindex" />
<title>@yield('title', 'Livewire Material')</title>
@vite(config('livewire-material.showcase.vite'))
@livewireStyles
</head>
<body class="min-h-screen antialiased">
@yield('content')
@livewireScripts
</body>
</html>