WireKit v2.58.0
Minor. An image can carry srcset, sizes, width, height and fetchpriority, Laravel Boost loads WireKit's own guidance, a clearable input names its clear button and says when it cleared, and date fields take a date object. Two ways a value from your data could run script are closed, in the editor's first paint and in link targets. Most of the rest is fixes: a prop value WireKit rejects renders the fallback it names, @wirekitScripts brings Livewire's scripts to a page without a Livewire component, a pager scrolls to its target under the CSP build, wirekit:install reports what failed, and diagnostic log lines stop repeating on every request.
Security
- The editor's first paint runs nothing from its value. With
format="html"the value was written into the page as it came, as the preview shown until the editor mounts, and the editor never reads that copy: an<img src=x onerror=…>in the value, fromold('body')for instance, ran as the page loaded. The preview is now rebuilt from an allowlist with PHP's HTML5 parser. It keeps the formatting elements and a few inert attributes, escapes all text, checkshrefandsrc, and drops elements whose content is not document text. Without PHP's DOM extension, which Laravel does not require, the preview stays empty until the editor mounts. - A link target that comes from your data can no longer run script. Citations in an assistant message, the rows of a notification center, from the server and in real time, status tiles, the rows and the create action of a scope switcher, and overflow-nav entries put their target into
hrefunchecked. They now keephttp,https,mailto,teland relative URLs, read the scheme the way a browser's URL parser does, and render an entry whose target is refused without a link: a static tile, a source as text, a row as a button. - The sandbox renderer tells its caller only that a render failed. It returned the exception's message, and a Blade error carries the view's absolute path on your server. The caller now gets
render failed, and the exception goes to your application's exception handler. - The sandbox audit log no longer keeps a reversible fingerprint of the client's address. It wrote a short unkeyed hash of the IP address, which a lookup table reverses. It now writes a digest of the client's network, an IPv4 /24 or an IPv6 /48, keyed with your application key, and
-when no key is set. Daily files older thanwirekit.sandbox.audit_log_retention_daysare deleted, 14 days by default;nullkeeps them all, andWIREKIT_SANDBOX_AUDIT_RETENTION_DAYSsets it from the environment. - A prop value WireKit rejects reaches your log quoted. Line breaks and other control characters are replaced and a value longer than 64 characters is shortened, so a value bound to user input cannot start a log line of its own. The same holds for an unknown icon alias and an unknown flag code. A rejection is logged once per request instead of once per render, so a component in a loop writes one line, not one per row.
Added
imagewritessrcset,sizes,width,heightandfetchpriorityon the<img>. They used to fall through to the<figure>, where they do nothing: a responsive source loaded at full size, and a box withoutratioreserved no space while the image loaded.fetchprioritytakeshigh,loworauto.- Laravel Boost loads WireKit's guidance. The package ships a Boost guideline with its conventions and a
wirekit-developmentskill with worked examples, andboost:installlistspushery/wirekitamong the third-party packages it found, so there is nothing to publish.wirekit:boost-skillsstill writes its manifest with the same options, and its description and success message say that Boost does not read that file. See Laravel Boost. - A clearable input names its clear button and says when it cleared.
clear-labelnames the button and its tooltip, and the field dispatcheswirekit:input-clearedonce after a clear, with the field's name indetail, so a search can drop the record it found. The events page lists it. calendar,date-pickerandtime-pickertake a date object forvalue,minandmax, and for both ends of a range. A Carbon instance from an Eloquentdateordatetimecast is written the way the field reads it, where it used to arrive asY-m-d H:i:s, which the calendar read as an invalid date and a native field as no value at all. The calendar also takes a range as its two ends,['start' => …, 'end' => …]or[$start, $end], as the date picker does.toggle-buttontakesactive-intent="primary", as the accent it is everywhere else in the catalog.
Changed
- A dropdown's entries are concentric with their panel. An entry's corner radius is the panel's radius minus its padding, as the rail's and the sidebar's already were; the dropdown panel sits in the overlay root, where that rule did not reach, so its entries kept the full radius. At the default scale an entry's corners go from 8px to 4px, and a submenu's entries sit 4px in from its walls.
- Diagnostic log lines appear once per hour, not once per request. The warning about a configured font preset whose CSS is not published, and the one about flag artwork that cannot be found, were meant to be logged once; under PHP-FPM every request starts afresh, so a lasting misconfiguration logged on every request. Both remember that they were logged in the application cache for an hour, and they still log when no cache is available.
wirekit:verifyreports a published config that only lacks newer options as information. Every release that added an option turned a--fail-on=warningrun red, although the new option already applied through the merge with the package's defaults. A key this version no longer reads is still a warning.- Control-scale boxes read the
--size-wk-*tokens. Avatars, the avatar group, the brand mark, the testimonial mark, feature and step markers, the OTP cells, the color-picker trigger and more used fixed Tailwind steps equal to a component height, so a theme that moved the tokens moved buttons and inputs and left them behind. They follow the tokens now, and the 24px pointer targets read--size-wk-target-min, so a denser theme cannot take them below the accessible minimum. At the default values nothing moves. The design tokens page names what each size token drives. - The standalone FAB button and the bottom navigation stack through
--z-wk-sticky, as the FAB already did, so a theme that moves the layer moves all three together. - The indeterminate progress bar animates
transforminstead ofleft, on the same path across the track, so the browser no longer lays it out on every frame. - The editor's notice about
window.tiptapEditorno longer announces a removal in 3.0.0. The name keeps working, and no removal is scheduled. composer.jsonnames the documentation and the product site.support.docspoints athttps://docs.wirekit.app, andhomepageathttps://www.wirekit.appinstead of repeating the source link.
Fixed
- A prop value WireKit rejects renders what its fallback renders. Where a rejected value does not throw, as on a web request by default, it is logged and replaced by the component's first allowed value, and in many components that value's name was written into the markup instead of what it stands for:
hero variant="nope"rendered a class nameddefaultand no background, an avatar lost its size, a container its width cap, andtextwith an unsupported line clamp clamped nothing. The fallback now renders exactly as if you had written it.heroandctafall back to their default sizes,lgandmd, where a typo gave the smallest. @wirekitScriptsbrings Livewire's scripts to a page without a Livewire component. Livewire adds its scripts, and the Alpine they carry, only to a page that renders a component, unless it is asked to.@wirekitScriptsmeant to ask and never did, so on a page with neither a Livewire component nor@livewireScriptsWireKit's interactive components did nothing. It asks now, except whenwirekit.scripts.bundleiscsp: that bundle brings its own Alpine, and a second one from Livewire would needunsafe-eval.- Personalizations, scopes and the
classesconfig reach five more components.chart,icon, the reading shell,replay-buttonand the table's reorder header rendered their classes past WireKit's class resolver, so a personalization or a scope for them changed nothing. They go through it now.WireKit::personalize()logs a warning in debug mode when it names a component that renders no class block of its own:faq-item,fonts,glass,structured-dataortoggle-button. wirekit:installreports every failed flag as a failure, and records an aborted run.--apex-licensereported success over a config file it had not written, and under--no-strict --ignore-failed-flagsa failed--presetended with "installed successfully". An install that stops after changing files now records the run, and--rollbackreverses that aborted run instead of the one before it. Whenwirekit:verifyfails at the end of an install, the install says so: without--ignore-failed-flagsit ends with "Install incomplete" and exit code 1; with it, the exit code stays 0 and the closing line names the problem.wirekit:installandwirekit:verifyread the Tailwind version that is installed, not the lower bound of a range.>=3.4or^3.4 || ^4.0read as v3, so the install aborted and verify failed on a project that runs v4. The installed package decides now; without one, only a constraint that names a single major version counts, and any other does not block.wirekit:installandwirekit:verifyread anapp.csswhose@sourceglobs look like comments. A glob such asviews/**/*.blade.phpcontains comment delimiters, and verify stripped the file from there to the next real comment, so it reported tokens and blocks after it as missing. The install skipped WireKit's@sourcewheneverwirekitand@sourceappeared anywhere in the file, and verify then reported the source missing. Both read the file with one parser that knows strings and comments.- A pager in Livewire mode scrolls to its target under Alpine's CSP build. With a
scrollTotarget outside the pager, such as a heading above the list, every page turn threw an error and scrolled nowhere. - Setting
expandedon an app rail orcollapsedon a sidebar wins over the state it stored. A rail rendered with:expanded="false"opened after an earlier visit had stored it open, and with the cookie driver the server's answer was replaced a frame after the render. When you set the state, the component no longer reads the store; it still writes to it. - Every folding sidebar section names its own panel. Two
sidebar.grouporsidebar.collapsiblesections with the same label, or two groups without one, rendered the same id, so the second trigger'saria-controlspointed at the first section. A repeated id now gets a suffix, and anidyou pass is used as given. - A sidebar label of one long word wraps inside the column instead of running past its edge, on
sidebar.itemand on asidebar.collapsibletrigger. - An open FAB speed dial shows its action names on a touch screen. They appeared on hover and keyboard focus only, so on a phone the open dial was a column of unlabeled circles.
hideLabelon an action still hides its name. align="start"andalign="end"on a toolbar place the items of its default slot. The slot's wrapper always spread its items apart, so a single button underalign="end"sat at the start.- A stepper's connecting lines follow a larger circle. The page taught a larger circle by changing the circle's size classes, while the lines stayed placed for the default circle and ran beside it.
--wk-stepper-circlenow sizes the circle, both connecting lines and the compact form's step width together; set it on one stepper or in a scope. It defaults to--size-wk-sm. - An animated radial progress moves its fill to a new value in every supported browser. The fill's transition relied on the browser interpolating between two gradients; it now transitions the value the gradient reads.
- The dark tint of the Liquid Glass
wk-glass-tier2layer applies. It looked for thedarkclass and the glass detector's class on two different elements, while WireKit sets both on<html>, so in dark mode the layer kept its light tint. Publish the glass assets again withphp artisan wirekit:glass install --forceto take the fix. - Escape on an app shell drawer that has just opened prevents its default, as it does once the drawer's focus trap is active, so a listener of yours finds the default prevented however quickly the reader presses it.
- A tool call announces when it settles. It promised a status announcement and had no status region. The region is now there from the first render, empty while the call is pending or running, and reads the tool's name and state once the call is done or has failed.
- A QR code reads every CSS hex form, and reports a color or error-correction level it does not know.
background="#fff"painted the quiet zone red-orange,color="red"drew a wrong color with a PHP deprecation notice, and an unknownerrorCorrectionfell back toLin silence.#rgb,#rgba,#rrggbband#rrggbbaaare read, an alpha becomes the fill's opacity, and any other value is reported like an invalid prop. structured-datakeeps its block valid when a value holds a bad byte, and renders none when JSON cannot hold a value. Invalid UTF-8,NANorINFmade the encoder fail, and the page carried an emptyld+jsonblock. A bad byte now becomes U+FFFD, and a failed encode renders no tag and logs the JSON error in debug mode. The schemas of breadcrumb and FAQ render through it and take the fix.highlightmatches letters beyond ASCII regardless of case, and never inside an HTML entity. "über" did not find "Über", and a query ofampmatched inside&, so the reader saw the entity as text. A query with an&now findsTom & Jerry.- Tour step numbers and FAQ schemas start fresh after each request and before each queued job. A render that stopped between a tour step and its tour left the next tour numbering from there, and under a queue worker an orphaned FAQ question could reach the next job's FAQPage schema.
- Values WireKit hands to Alpine read back the same in every CSP build. The CSP builds of Alpine and Livewire read some JSON escapes back as plain letters, so a value containing a form feed or a line separator arrived changed. Line and paragraph separators are now written as themselves and other control characters as U+FFFD; newline, tab and carriage return keep their escapes.
- A treemap tooltip stays at the hovered cell with ApexCharts, where it sat about 130px away and stayed there wherever the pointer moved.
- A custom chart adapter's scripts load.
ChartAdapter::scripts()promised that its URLs would be loaded, and nothing read it, so a chart drew nothing and said nothing. The chart component now writes one deferred<script>per URL per response, with the page's CSP nonce. A script that arrives with a Livewire update does not run, as the contracts page says. - An unsupported chart type suggests switching libraries only where the other library draws it, and otherwise the nearest type names of the active library, such as
pie, lineforlnie. - A map passes MapLibre's errors on. Its listener had silenced MapLibre's own console output and reported every error as the same hint about CSP and the network, once. Each error is now logged with the original error object, and the load-failure hint appears for a failed request only.
- The Tailwind source of tabs carries the classes its styles build at runtime: the active tab's underline and the separators of the
borderedvariant. An application that scans only the sources of the components it uses got them only when another source happened to carry them. - Hover dims, a code font and a disabled opacity follow their tokens.
link,data-table,stepper, the toast region andproduct-carddimmed on hover by a fixed amount, so a preset that sets--opacity-wk-hoverchanged nothing there; code cells in a data table ignored the theme's monospace font; andbranch-switcherset its own disabled opacity. A link also fades to its dim now instead of jumping. - The editor's placeholder sits inside the empty paragraph in Chrome and Edge 111 to 117. It floated to
inline-start, which those versions do not know, so the placeholder became a box before the paragraph and the caret sat after its text. It floats left now, and toinline-startwhere the browser supports it, so a right-to-left editor keeps it at the start. - A reaction's glyph asks for its emoji form. Its class compiled to a font weight the browser dropped. Browsers that support
font-variant-emojinow draw the emoji form. - A color picker's native readout sits 12px from its swatch, as intended; two gap classes competed, and the smaller one won.
- An attachment rounds a file size before it chooses the unit and the decimals, so 9.96 MB reads
10 MBrather than10.0 MB, and 1023.999 KB reads1.0 MBrather than1024 KB. - A usage meter reads a limit of 0 as over it, with its status, marker and danger intent, at
0 / 0as at3 / 0; before, it said nothing. - A table's debug warning finds raw rows around sub-component cells. A raw
<thead><tr>aroundtable.thcells passed the check while the rows lost their dividers, stripes and hover. A table nested in a cell is not counted as part of it. - The unknown-prop warning tells an event handler from a misspelled prop that starts with
on, and knows every global HTML attribute. Any name starting withonpassed as a handler, soonLableon a toggle button was never reported. Only a lowercase name that is not one edit away from a declared prop passes now, and a camel-caseonClickis reported.popover,writingsuggestions, the microdata attributes,headingoffsetandheadingresetno longer log an unknown prop. wirekit:csp-auditchecksx-wk-findableand each branch of a Blade block inside an attribute. An arrow function onx-wk-findablewent unchecked, and a value with@if … @endifinside it landed among the expressions the audit could not read, which nothing reported. Each branch is now parsed, a fault that every branch shares is reported once, andscannedcounts attributes.wirekit:doctor:propstells the parenthesis form of a slot closing tag glued to text from the others. After a parenthesis Blade closes the slot and loses only the text in parentheses; after a word it prints the directive as text. The finding now says which of the two happened.wirekit:makelists the method awire:pollorwire:initcalls among the members you have to write, after a modifier with a hyphen such as.keep-alivetoo.wirekit:editor-presetand the editor page register each Tiptap 3 extension once. Tiptap 3's StarterKit includes Link and Underline, and the snippet added both again, so Tiptap warned about the duplicates and the second Link keptopenOnClick: true. Link is configured insideStarterKit.configure()now, and the collaboration recipe uses Tiptap 3'sundoRedo: falseandCollaborationCaret.- The schema file
wirekit:installwrites, the MCP catalog and the Boost manifest list only published components. Components still in preparation appeared there with their API.wirekit:export-json --publicwrites the same set. - The MCP tool
get_component_examplesanswers a component documented on another component's page with examples that render it, where it returned that page's first previews. - The Boost manifest lists the
wirekit:*commands Artisan registered, with their full names and descriptions. A name with a digit was cut short,wirekit:doctor:a11ycame out aswirekit:doctor:a, and a description ended at its first quote. timeline'svariantis described as the free styling hook it is inwirekit:show,wirekit:export-jsonand.wirekit-schema.json, which offered two built-in layouts that do not exist.- The shipped AI guidance teaches props that exist. The Cursor rules called
secondarya legacyvariantvalue that maps tointent="neutral", whilebuttonandbadgehave novariant; they andAGENTS.mdgavesectionagapprop it does not have; and the Cursor rules allowed four CSS features newer than the supported browsers.wirekit:cursor-rulesand the MCPconventionstool carry the corrected text. - The
@wirekitTransitiondirective works. Every use of it ended in a parse error, and the classes it named ignored the motion tokens. It writes the transition attributes with the token utilities the components use.
Documentation
- The README's theming example works. It wrapped the token override in
@layer base, and a layered rule loses to WireKit's unlayered stylesheet, so the accent stayed at its default. It is a plain:rootrule now, as on the scrollbar and tabs pages, which dropped the same wrapper, and the README's install steps match Getting Started. - The published
config/wirekit.php, the component comments and the prop tables of brand, hero and tooltip say when an invalid prop throws, as strict validation describes it: only while the gate is strict and throwing is on, which by default means a console or test run withAPP_DEBUGon. A web request logs the value and renders the fallback, and understrict=falsenothing throws, whateverthrow_on_invalidsays. The config also says what a missing icon package does: a web request renders the icon placeholder and logs the package to install, and a console or test run throws. - The fonts page says what Safari shows with the matched fallback fonts: it applies
size-adjustfrom version 17 and none of the three metric overrides, so a paragraph with a numeric line height lands within a line of the web font's height, while text withline-height: normalkeeps the local face's line metrics. - The structured data page says that a Content Security Policy does not apply to a JSON-LD block, so a strict policy leaves your structured data alone, and that
@jsonwritten over an array literal takes the text after the first comma as its flags and loses the escaping. - The price page names the reference units for a unit price as the German, EU, British and US rules state them, with a link to the German regulation.
- The FAQ page no longer grounds its schema in Google's FAQ rich results, which Google has stopped showing, and
Schema::webSite()no longer suggests a search action as the usual one. - The sandbox schema's documented shape names
allowed_schemes, the check that keepsjavascript:out of anhref,srcoraction; a schema you register needs it on every such prop.
Components
Every component this release changes, each linked to its page: Accordion · Alert Dialog · Announcement Banner · App Rail · App Shell · Attachment · Avatar · Band · Blockquote · Bottom Nav · Branch Switcher · Brand · Brand Bar · Button · Calendar · Card · Carousel · Chart · Color Picker · Combobox · Container · CTA · Data Table · Date Picker · Dropdown · Editor · Empty State · Event Calendar · FAB · FAQ · Feature · Feature Grid · Footer · Grid · Heading · Hero · Highlight · Icon · Image · Indicator · Inline Edit · Input · Kbd · Lightbox · Link component · List · Main · Map · Message · Message Group · Multi-Select · Navbar · Notification Center · OTP Input · Overflow Nav · Page Header · Page Progress · Pagination · Price · Pricing Table · Product Card · Profile · Progress · Progress Radial · Prose · QR Code · Rating · Reaction · Reading · Replay Button · Reveal · Row · Scope Switcher · Section · Segmented Control · Shell Bar · Sidebar · Skeleton · Slider · Stack · Status Tiles · Step Marker · Stepper · Stream · Strength Meter · Structured Data · Table · Tabs · Testimonial · Text · Theme Controller · Ticker · Time Picker · Timeline · Toast · Toggle Button · Tool Call · Toolbar · Tooltip · Usage Meter