WireKit v1.3.0
Minor release covering eight new blueprint primitive components, an Artisan
command suite for scaffolding / diagnostics / asset publishing / AI-tooling
integration / machine-readable manifests, the Livewire sandbox primitives library,
and a security-hardening sweep across target="_blank" link rendering plus the
JSON-encoder layer.
No breaking changes — fully backward-compatible with v1.2.x.
Added
-
Blueprint primitive components (8) —
<x-wirekit::(currency formatting with size variants),price> <x-wirekit::(timeline / chat date divider),date-separator> <x-wirekit::(emoji reaction button with count),reaction> <x-wirekit::(live data ticker with delta indicator),ticker> <x-wirekit::(button group bar with slots),toolbar> <x-wirekit::(chat / thread message bubble with alignment),message> <x-wirekit::andkanban> <x-wirekit::(kanban board with column composition). All use design tokens exclusively, support the Intent × Surface API where applicable, and follow WAI-ARIA patterns.kanban-column> -
Sandbox primitives library (
src/Sandbox/) — reusable security-hardened render pipeline for any developer project that needs to render WireKit components from untrusted JSON props (live-preview iframes, prop-editor UIs, etc.):SandboxRenderer::— main entry point. Validates → sanitizes → renders → audit-logs. Returnsrender($component, $props, $ip): RenderResult RenderResult(success or 422-shaped rejection); never throws.PropsValidator— enforces per-component prop schema, type-checks, rejects strings >10 KB and arrays nested >5 deep (DoS defense), HTML-escapes every string defense-in-depth so even a slot using{!! !!}cannot surface raw payload content.Component— strict kebab-case regex +Allowlist Componentcross-check + sandbox-schema presence guard. Path-traversal characters, namespace separators, whitespace, uppercase — all rejected with 422-shape, never 500.Registry Sandbox— in-memory registry of per-component prop allowlists withSchema Registry allowed_valuesenums. Initial coverage of 11 starter components (button, badge, callout, alert, card, code, code-block, kbd, heading, text, link); the renderer is functional with whatever schemas are seeded, full coverage will follow incrementally.SandboxAuditLog— file-based daily-rotating log (storage/). IPs sha256-truncated to 16 chars so logs are useful for rate-pattern auditing but not for tracking individuals.logs/ sandbox/ YYYY-MM-DD. log RenderResult/Validation— immutable result objects with public-readableResult ok/violations/html/schemaproperties so developer-side prop-editor UIs can read them viaget_.object_ vars()
-
<x-wirekit::dark-mode contrast fix — switched the delta text from the bareticker> --color-wk-success/--color-wk-dangerfoundation tokens to the*-textvariants (which are calibrated for ≥4.5:1 WCAG 1.4.3 contrast against surface tokens in BOTH light and dark mode). -
.cursor/— single-file (~150-line) Cursor rules ruleset covering component invocation syntax, the Intent × Surface variant system, design tokens, icon usage, layout primitives, typography primitives, modal / drawer / dropdown trigger patterns, accessibility defaults, Livewire integration patterns, browser-support baseline, and the full CLI. Cursor / Codeium / other nativerules/ wirekit. mdc .mdceditors pick up the rules automatically for every*.blade.phpand*.cssfile in the project. -
php artisan wirekit:component {name}— scaffolds a custom Blade component derived from a WireKit base intoresources/.views/ components/ custom/{name}.blade. php --baseflag picks the source;--forceallows overwriting an existing custom file. Resolves both flat (button) and dotted (card.header) base names. (The v2.0.0 default of--base={name}was superseded in v2.1.0 by a derived-parent default —wirekit:component my-buttonnow derives--base=buttonautomatically; see the v2.1.0 entry.) -
php artisan wirekit:publish-icons {preset}— targeted icon publishing. Copies a single preset's SVG directory fromvendor/{package}/resources/tosvg/ public/. Refuses with a precisevendor/ wirekit/ icons/{preset}/ composer require ...fix line when the underlying icon-set package is not installed. Supportsheroicons,heroicons-app,heroicons-marketing,lucide,phosphor,tabler. -
php artisan wirekit:doctor— alias forwirekit:verifyunder the more conventional Laravel-ecosystem name. Existing CI scripts and docs that reference either name keep working. (The v2.0.0 shipped two parallel registrations; v2.1.0 collapses them to a single Symfony alias — see the v2.1.0### Changedentry for the internal-import consequence.) -
php artisan wirekit:cursor-rules— copies the package's.cursor/into the developer project'srules/ wirekit. mdc .cursor/rules/directory.--forceto overwrite an existing copy. -
php artisan wirekit:export-api-map [--pretty]— emits an AI-friendly hierarchical sitemap covering eight groups: components, themes, fonts, icons, layouts, blueprints, recipes, and commands. Superset ofwirekit:export-json. Output is XSS-safe viaJSON_HEX_TAG. Designed for MCP servers and other AI tooling that need a single entry point to enumerate every WireKit surface. -
php artisan wirekit:export-blocks [--pretty]— emits a machine-readable JSON manifest of every layout + blueprint with frontmatter metadata (category,tags,dependencies,responsive,dark_compatible) plus generatedpreview_urlandsource_url. Consumable by gallery UIs and AI tooling for filterable browsing. -
Password input accessibility — toggle button has a static
aria-labelfallback for pre-Alpine-hydration accessibility scans. -
Toggle auto-labeling — component auto-generates an
aria-labelfrom thenameprop when neitherlabelnoraria-labelis provided. -
Config defaults —
config/ships size defaults forwirekit. php <x-wirekit::andprice> <x-wirekit::.ticker>
Changed
Pushery\now carries a public-readableWireKit\ Sandbox\ RenderResult ?array $schemaproperty in addition took/html/violations.SandboxRenderer::echoes the per-component schema back so developer-side prop-editor UIs can render the editor without a second round-trip to the schema registry.success() target="_blank"auto-protection hardened — therelattribute injection in all 13 link-rendering components (Button, Dropdown Item, Command Palette Item, Menubar Item, Navigation Menu Item, Navigation Menu Link, Navbar Item, Sidebar Item, Link, Brand, Card) now uses an explicit override pattern that prevents caller-suppliedrelvalues from silently defeating thenoopener noreferrerprotection. Coverage extended to four additional components that were previously missing the pattern: Link, Navbar Item, Navigation Menu Link, and Sidebar Item.- Chart.js dark-mode refresh —
chart.update()replaceschart.in the MutationObserver callback. Chart.js v4'supdate('none') 'none'mode skips the style-resolver pass when only color properties change, leaving stale colors rendered. The observer now watches both<html>and<body>for.darkclass changes, supporting both mounting conventions.
Fixed
-
WCAG 1.4.3 dark-mode contrast on
<x-wirekit::delta text — theticker> --color-wk-success/--color-wk-dangerfoundation tokens previously yielded 3.66:1 / 4.05:1 against dark surface tokens (fails the 4.5:1 AA threshold for small text). Fix uses the*-texttoken variants which are calibrated for ≥4.5:1 in both modes. -
CTA accent variant dark-mode contrast — the accent variant used a hardcoded
text-whiteclass that fails when--color-wk-accentinverts in dark mode. Now usestext-[var(--color-wk-accent-fg)]which auto-switches correctly. -
Section accent background token — the accent background variant referenced a non-existent
--color-wk-primaryCSS variable. Replaced with--color-wk-accentbackground and--color-wk-accent-fgtext color, matching the established pattern used by CTA and Badge. -
Dropdown trigger ARIA —
aria-haspopup,aria-expanded, andaria-controlswere placed on a non-interactive<div>wrapper. Moved to the inner interactive element viax-init. -
Progress bar accessible name — component only wired
aria-labeledbywhen thelabelprop was set. Usages without labels now receive a sensible"Progress"default. -
App-shell sidebar backdrop — the mobile sidebar dim overlay was traversable by screen readers, defeating the focus-trap intent. Added
aria-hidden="true". -
dist/parses correctly when loaded viawirekit. css <link>. Previously the entire token palette lived inside a Tailwind v4@theme {}compiler block. Browsers correctly skip unknown at-rules per the CSS spec, which meant the documented "fastest path" — using the@wirekitStylesBlade directive that embeds the file via<link rel="stylesheet">— left zero--color-wk-*variables defined in the CSSOM. Components rendered without color tokens. The file now emits a standard:root {}(light) and.dark {}(dark) block directly, so both consumption paths resolve identically: the@wirekitStylesdirective AND@importfromapp.css. The@custom-variant dark (&:where(.dark, .dark *));directive is preserved at the top of the file (harmless under<link>, useful under@importfor Tailwinddark:variant support). -
WCAG 1.4.3 contrast — light-mode
*-textandtext-mutedtokens recalibrated. Three "soft-bg foreground" tokens were below the AA 4.5:1 threshold against the 12%color-mix()soft-tone backgrounds used by badge / alert / callout / feature / message / reaction / toast-region, andtext-mutedwas below threshold onbg-muted:--color-wk-success-text: green-700 → green-800. Was 4.33:1 on soft-success bg, now ~6.17:1.--color-wk-danger-text: red-500 → red-700. Was 3.89:1 on soft-danger bg, now ~5.13:1.--color-wk-warning-text: amber-700 → amber-800. Was 4.41:1 on soft-warning bg, now ~6.04:1.--color-wk-text-muted: neutral-500 → neutral-550. Was 4.26:1 onbg-muted(#f7f7f7), now ~6.13:1.text-subtleandtext-placeholderare unchanged (they only appear on white where neutral-500 already meets 4.74:1).
-
Bare
text-[var(--color-wk-{success,warning,danger})]on text content swept to*-textvariants. Affected component-internal usages:<x-wirekit::semantic variants (text> success/warning),<x-wirekit::stat> uptrend,<x-wirekit::delta intent (price> success/danger),<x-wirekit::soft tones (feature> success/warning). Decorativearia-hiddenSVG icons inside alert / callout / toast-region / code-block / rating left at the bare tone (graphic-element semantics, 3:1 threshold via WCAG 1.4.11). -
<x-wirekit::event chips no longer render white text on green-500 / amber-500. Month-view and week-view event chips (calendar> background: var(--color-wk-success); color: var(--color-wk-bg)) yielded 3.21:1 / 2.13:1 — fail. Component now usescolor: var(--color-wk-success-fg)/color: var(--color-wk-warning-fg)(zinc-900 on the tone bg — ~6.95:1 / ~9.03:1). -
<x-wirekit::week-view chip subtexts collapsed. Opacity-blended subtexts (calendar> <span style="opacity: 0.8">…</span>) dropped contrast below 4.5:1 in light mode (4.23:1 against the tone bg). Replaced the two-linePrimary+ opacity-dimmed subtext pattern with a single-linePrimary · Subtextmiddle-dot label that passes both modes at the full token contrast.
Security
/components.JSON encoder hardened withjson JSON_HEX_TAG— bringswirekit:export-jsonin line with the existingwirekit:export-api-mapandwirekit:export-blockscontracts. WithoutJSON_HEX_TAG, a component description containing</script>could break out of a<script type="application/block where the manifest is embedded.ld+json">