ComponentBook
The components the panel can compose with: the dashboard primitives of `milpa/live`, the shell's own two (`admin-sidebar`, `admin-section-header` — painted by {@see ShellHtmlRenderer}), plus every custom component the sections bring — one or a whole {@see \Milpa\Admin\Section\DeclaredView} of them. Built fresh per request — the registry of `milpa/live` is a plain map with no discovery, and the sections are discovered per request too, so the book follows them. A section that names a component nobody registered fails here, with the list of what exists. **One registry, in layers** (greenhouse decisions/0211). The book is a {@see CompositeComponentRegistry}: the panel's own layer first, then ONE layer per section that brought components, labelled with the section's id. That is what lets a single live endpoint serve the host's components and every guest's, and what makes shadowing loud instead of silent: two sections binding one name to DIFFERENT definitions throw {@see ComponentNameConflictException} naming the component and both sections, exactly as two plugins declaring one section id throw {@see \Milpa\Admin\Section\SectionConflictException}. The rule is `milpa/live`'s own — identity or a stateless class — not a second one invented here: two sections that reuse the SAME instance, or two instances of a class with no state, are one definition and no conflict. The RENDERER is held to the same rule, by the book itself ({@see RendererConflictException}). Two sections that legitimately share one definition may still each bring their own renderer, and the renderer registry resolves the last one registered: without this the first section's surface would be painted by the second's renderer, silently, in the one place whose whole point is that a collision is loud. Sharing the renderer instance (or a stateless class) is agreement; anything else names both. The names the book registers itself — the primitives and the shell's own two — are the host's: a section may NAME one (a `metric-card` section is the normal case) but never bring its own definition under it. A layer of its own would not save it: the panel's layer resolves first, so the guest's definition would be dead weight the endpoint could never reach; the book refuses instead ({@see ReservedComponentException}), which is what lets the header say a section never names its own declarer.
ComponentBook::__construct()
public function __construct(Milpa\Live\Contracts\Transport\StateTransferCodecInterface $codec, ?Milpa\Interfaces\Event\MilpaEventDispatcherInterface $events = null):Parameters
| Name | Type | Description |
|---|---|---|
| $codec | Milpa\Live\Contracts\Transport\StateTransferCodecInterface | |
| $events | ?Milpa\Interfaces\Event\MilpaEventDispatcherInterface |
ComponentBook::forSections()
public static function forSections(Milpa\Admin\Section\SectionCatalogue $catalogue, Milpa\Live\Contracts\Transport\StateTransferCodecInterface $codec, ?Milpa\Interfaces\Event\MilpaEventDispatcherInterface $events = null): selfA book that has already adopted every section of a catalogue — what a page compiles with and what the live wire re-renders from, built the same way on both sides so an envelope signed by one is resolvable by the other.
Parameters
| Name | Type | Description |
|---|---|---|
| $catalogue | Milpa\Admin\Section\SectionCatalogue | |
| $codec | Milpa\Live\Contracts\Transport\StateTransferCodecInterface | |
| $events | ?Milpa\Interfaces\Event\MilpaEventDispatcherInterface |
Throws
UnknownComponentException when a section names a component nothing registered
ReservedComponentException when a section redefines one of the panel's own
ComponentNameConflictException when two sections bind one name to different definitions
RendererConflictException when two sections bring different renderers for one name
ComponentBook::register()
public function register(string $name, Milpa\Live\Contracts\Component\ComponentDefinitionInterface $definition, Milpa\Live\Contracts\Rendering\ComponentRendererInterface $renderer): voidRegisters one component under a name, with the renderer that paints it — the book's one way in.
Parameters
| Name | Type | Description |
|---|---|---|
| $name | string | |
| $definition | Milpa\Live\Contracts\Component\ComponentDefinitionInterface | |
| $renderer | Milpa\Live\Contracts\Rendering\ComponentRendererInterface |
ComponentBook::adopt()
public function adopt(Milpa\Admin\Section\AdminSection $section): voidMakes a section renderable: registers everything it brings — one component or the whole tree of a declared view — under its own layer, or checks that the one it names exists.
Parameters
| Name | Type | Description |
|---|---|---|
| $section | Milpa\Admin\Section\AdminSection |
Throws
UnknownComponentException when the section names a component nothing registered
ReservedComponentException when the section brings its own definition under a name the book
registered itself — a primitive, or one of the shell's own
ComponentNameConflictException when another section already bound one of those names to a
different definition
RendererConflictException when another section already bound one of those names to a
different renderer
ComponentBook::registry()
public function registry(): Milpa\Live\Contracts\Component\ComponentRegistryInterfaceThe registry the compiler and the live endpoint resolve component names against — every layer.
ComponentBook::renderers()
public function renderers(): Milpa\Live\Rendering\ComponentRendererRegistryThe renderers, answering per component name — the pair of the composite registry.
ComponentBook::names()
public function names(): arrayThe names the book can render — the primitives, then the shell's own, then the sections' — in registration order, each once.
ComponentBook::compiler()
public function compiler(array $defaults = []): Milpa\Live\Rendering\XhtmlComponentCompilerA compiler over this book, with default props per component name.
Parameters
| Name | Type | Description |
|---|---|---|
| $defaults | array<string, array<string, mixed>> | component name → props merged under the markup's attributes |