Contracts — ChartAdapter and IconPreset
Most of WireKit is extended by composing components and overriding tokens. Two things are extended by implementing an interface instead, because the package has to call your code rather than the other way round: adding a chart library it does not ship, and adding a set of icon aliases.
Both live in Pushery\. Neither is abstract-class-based — they are plain
interfaces with no base to inherit, so nothing in your implementation is inherited by accident.
ChartAdapter — teach the chart component a new library
WireKit ships adapters for Chart.js and ApexCharts and bundles neither library. An adapter is
the translation layer between the <x-wirekit:: API and one library's option shape.
ApexCharts is not MIT-licensed — the free Community License covers organizations under $2 million USD annual revenue, and above that a Commercial License is required. That applies to the library you install, never to WireKit's adapter glue, which is MIT either way. See the License section on the Chart overview or apexcharts.com/license for the canonical text.
use Pushery\WireKit\Contracts\ChartAdapter;
final class MyChartAdapter implements ChartAdapter
{
// 1. Stable slug used in error messages and config comparison. It must NOT change
// across patch releases — a developer's config names it.
public function name(): string
{
return 'my-charts';
}
// 2. Script URLs the page needs, when the library is not installed from npm, in the
// order they must run. Return an empty array when the developer installs the
// library themselves, which is what both shipped adapters do.
public function scripts(): array
{
return [];
}
// 3. Translate WireKit's labels + datasets into the library's own data shape.
public function normalizeData(string $type, array $labels, array $datasets): array
{
return ['labels' => $labels, 'datasets' => $datasets];
}
// 4. Per-type option defaults — tooltips, legends, axes.
public function defaultOptions(string $type): array
{
return [];
}
// 5. The Alpine factory that mounts it, and what that factory renders into.
public function alpineComponent(): string
{
return 'myChart';
}
public function rendersTo(): string
{
return 'canvas';
}
// 6. Every type this adapter accepts. `<x-wirekit::chart type="…">` is validated
// against it, so a type missing here is rejected before your code runs.
public function supportedTypes(): array
{
return ['bar', 'line'];
}
}
When ChartAdapter:: returns URLs, the chart component loads them for you: one deferred <script>
per URL, next to the first chart that uses your adapter, never twice on the same page however
many charts ask for it, and carrying the page's CSP nonce. Deferred scripts run once the page is
parsed, in the order you listed them, and before the script Livewire injects starts Alpine, so
the library is there when your Alpine factory builds the chart.
A script tag that arrives in a Livewire update never runs. If a chart using your adapter is not on the page when it first loads and only appears after an update, load the library in your layout instead, or install it from npm and return an empty array.
Register it by pointing the chart config at your class:
// config/wirekit.php
'charts' => [
'library' => \App\Charts\MyChartAdapter::class,
],
ChartManager verifies your class implements ChartAdapter before instantiating it, so a
class that merely looks adapter-shaped fails with a clear message rather than a fatal partway
through a render.
IconPreset — add a set of icon aliases
An icon preset maps WireKit's semantic alias names (close, search, chevron-down) onto one
icon family's identifiers, so a component can ask for a concept and get whatever the active
family calls it.
use Pushery\WireKit\Contracts\IconPreset;
final class MyIconPreset implements IconPreset
{
// 1. alias => Blade Icon identifier.
public function icons(): array
{
return [
'close' => 'my-x-mark',
'search' => 'my-magnifier',
];
}
// 2. The composer package that must be installed for those identifiers to resolve.
// Surfaced by `wirekit:doctor` when it is missing.
public function requires(): string
{
return 'vendor/my-icons';
}
}
// config/wirekit.php — presets stack, later entries win, and a developer-level
// alias overrides all of them.
'icons' => [
'presets' => ['heroicons', \App\Icons\MyIconPreset::class],
],
The four base presets — heroicons, lucide, phosphor, tabler — must all define the same standard aliases, and a test enforces that parity. A stackable preset like your own may define as few as one: it is layered over a base rather than replacing it.
This rule covers the aliases WireKit itself ships, and it applies the moment you propose one upstream: an alias that resolves in three families and substitutes something merely similar in the fourth reads as a contract and is not one. Switching families then silently draws the wrong glyph — nothing errors, nothing logs, and the icon is simply not the one the component asked for. Your own preset is yours to shape; the shared alias set is not.
See Also
- Chart — the component an adapter serves
- Icon — presets, aliases and the shipped families
- ComponentRegistry — discovering components from PHP