nyoncode / wire-panels
Application owner layer for wire: resources and their pages.
Requires
- php: ^8.2
- illuminate/database: ^12.0|^13.0
- illuminate/support: ^12.0|^13.0
- livewire/livewire: ^4.0
- nyoncode/laravel-package-toolkit: ^2.5.0
- nyoncode/wire-core: 2.0.0
- nyoncode/wire-forms: 2.0.0
- nyoncode/wire-table: 2.0.0
Requires (Dev)
- laravel/pint: ^1.29
- orchestra/testbench: ^10.0|^11.0
- pestphp/pest: ^4.0|^5.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
Wire Panels
The application owner layer for Wire: one entity, declared once, with the surfaces it exposes.
use NyonCode\WireCore\Core\Resources\Concerns\DescribesRecords; use NyonCode\WireCore\Core\Resources\Contracts\DescribesResource; use NyonCode\WirePanels\Resources\Contracts\ProvidesResourceTable; final class OrderResource implements DescribesResource, ProvidesResourceTable { use DescribesRecords; public static function modelClass(): ?string { return Order::class; } public function table(Table $table): Table { return $table->columns([TextColumn::make('number')]); } }
// config/wire-core.php 'resources' => [App\Resources\OrderResource::class],
final class ListOrders extends \NyonCode\WirePanels\Resources\Pages\ListPage { protected static ?string $resource = OrderResource::class; }
What ships where
A resource is declared across the packages that own the types it names, so an application installs only what its resources actually use:
| Package | |
|---|---|
DescribesResource, DescribesRecords, ResourceRegistry, Workspace, NavigationItem, ProvidesNavigation |
wire-core |
ProvidesResourceForm |
wire-forms |
ProvidesResourceInfolist |
wire-core (beside Infolists) |
ProvidesResourceTable, ProvidesRelationManagers, every page |
this package |
The practical consequence: a resource with a form and no list needs wire-forms
and nothing else. This package sits above every component package — it requires
wire-table, wire-forms and wire-core, and nothing requires it. That direction is
the point: a resource composes the primitives, so the package that owns resources
is the one allowed to name all of them, and none of them may name it back.
Pages
| Page | Host trait | Reads |
|---|---|---|
ListPage |
WithTable |
ProvidesResourceTable |
CreatePage, EditPage |
WithForms |
ProvidesResourceForm — one form() serves both |
ViewPage |
none | ProvidesResourceInfolist |
ViewPage composes no host trait on purpose: read-only means no state to bind
and nothing to submit.
Every page also works with no resource at all — write table() or form()
on the page and it is an ordinary WithTable/WithForms component. A page left
half declared throws rather than rendering empty, because empty reads as
"nothing here" instead of as a mistake.
Edit and view take a record key, not a model:
@livewire(EditOrder::class, ['record' => $order->getKey()])
Mount arguments land in the Livewire snapshot, where a hydrated model is both larger than the key and stale by the next request.
Not a panel builder
No routing, no URL shell, no navigation tree. ResourceRegistry holds class
names and answers two questions about them; Workspace groups and orders the
menu. What renders any of it is the application's.
Documentation
Full docs: docs/panels/resources.md
(česky).
License
MIT.