Skip to main content
WireKit

WireKit v2.38.0

Minor release

Minor. The overlay work of the last two releases reached the drawer: its geometry ships in the stylesheet now rather than depending on your Tailwind build, and the panel became a real dialog instead of one that only looked like it. Alongside that, three layout defects that each cost a visible jump on a page load, and a row that lines its form controls up whatever mix of labels they carry.

Added

  • A <x-wirekit::data-table> column takes a subKey, so a cell can be two lines. The ordinary shape of an admin table is a value over a quieter second one — order number over date, customer over email, product over SKU — and a column could previously render only a single string, a number or a status pill. A row whose second field is empty draws one line rather than one line and a gap. On a number column both lines stay tabular. See Data Table.
  • <x-wirekit::product-card> takes a media slot and a badge slot. image is a URL, and there was no branch for its absence — so a product whose artwork is drawn rather than photographed, or is a video or a color field, had no way into the component at all. The slot wins over image when both are given, and with neither the card draws no media area, which is deliberate: a placeholder invented here would appear on every card that legitimately has no picture. The badge slot sits beside the ones the card derives — those answer on-sale and in-stock, and "New" or "Limited" had no equivalent — and the two stack rather than overlapping. See Product Card.
  • <x-wirekit::row align-fields> puts every control in a row on one line, and stacks them below 48rem. A labeled field is taller than an unlabeled one and a field with a hint is taller still, so no single align value lines the controls up for every mix — and a submit button beside them has no label row at all. The row becomes three shared tracks (labels, controls, messages) and each field hands its parts to them. Opt-in: it changes the row's display model, and align / justify stop applying while it is on. See Row.
  • <x-wirekit::app-rail.item as="button">. A rail entry that opens a menu is not a destination, and as a link it was subtly broken: a link activates on Enter and not on Space, so the key did nothing. Every click on the placeholder href also pushed a history entry and wrote a bare # into the address bar. See App Rail.
  • <x-wirekit::app-rail persist-driver="cookie">. persist keeps the reader's choice in localStorage, which no server can read — so a rail that remembers being expanded renders collapsed and widens itself after the first paint. A cookie is the only store Blade and Alpine both read, so the first render is already right. Opt-in, because writing a cookie is something an application has to be able to account for. See App Rail.
  • wirekit:doctor says what a stale published asset costs. "Outdated" undersold it: the Blade directives compare size and hash, decide a stale copy cannot be trusted, and serve the package route instead — so every asset travels through PHP, without the cache headers or the precompressed sibling configured for public/vendor/. The report names that now, once per run. See CLI Reference.
  • Two design tokens, --size-wk-drawer-inset and --size-wk-rail-icon. Both were literals repeated across rules that had to agree; each is one value now. See Design Tokens.

Fixed

  • An icon whose set is not installed renders a placeholder instead of a 500. The component degraded for two of the three ways an icon can go missing: blade-icons absent, and an alias nobody has. The third is an alias that resolves perfectly onto a set nobody registered — inbox becomes heroicon-m-inbox out of a static table that never checks whether the glyph is there — and that name reached the renderer, found neither the set nor a fallback, and threw. Icons draw transitively through buttons, dropdowns and modals, so the page it took down was most pages. It is the state an application lands in by accident: one that already had blade-icons for its own set reads the set package as optional. The log line names the package to install, once per prefix rather than once per icon, and a fallback you configured still wins. A console command or a test still fails loudly, because there the missing package is fixable now. See Icon.

  • A restarted <x-wirekit::stat> counter no longer stays on zero when its frames stop after the first one. The counter carries a watchdog for exactly that case — a frame that is hidden or unpainted pauses requestAnimationFrame indefinitely while timers keep running — and the watchdog was being called off by the first frame that landed. One frame does land: it writes zero and is then never followed, so the one state the net was there for was the one state that took it down. The watchdog now decides by whether the run actually finished. See Stat.

  • The scope-collision warning no longer fires at developers whose scope is fine. It told a caller their x-data was discarded whenever the component's own template mentioned one — but it read the template with a pattern that cannot see conditions, and a large minority of components set theirs only inside one. <x-wirekit::card> is the case that surfaced it: its x-data belongs to a debug warning that renders only when a card is composed wrongly, so a correctly composed card collides with nothing and the message asked for working code to be rewritten. The check now asks whether the component sets one on every render, which is the claim the message makes. A component that sets one both ways still warns.

  • The workspace mark in an expandable <x-wirekit::app-rail> now shows its name when the rail expands. The mark decided that in PHP, from labels, while rendering — and widening the rail is a browser-side change that happens long after, so a rail that started narrow kept its name hidden at every width. Move the workspace name out of your header because the rail was meant to carry it, and it was nowhere. The failure was silent: the name was in the document and announced, merely never drawn. The mark now reads the same live state its modules read. See App Rail.

  • The drawer's panel gets its geometry from the stylesheet, not from your Tailwind build. Its position, size and edge came from bare utility classes, which exist only where a build scanned this package — so an application that did not would get a panel with no position at all. Alert dialog and modal already shipped theirs; the drawer was the one that did not. See Drawer.

  • The navigation drawer is a dialog to the keyboard, not only to the mouse. Below the breakpoint it slid over the page like a modal sheet and had none of a dialog's semantics: no role, no aria-modal, no focus trap, and Escape did nothing. Tab walked straight out of it into the page behind. See App Shell.

  • An expanded rail no longer makes the mobile drawer wider than the phone. The drawer took the rail's expanded width with it, so a reader who had expanded the rail on a desktop got a sheet wider than the viewport on their phone. See App Shell.

  • The shell's columns stay in the layout above the breakpoint while the page is still booting. A shell column is a drawer below lg and an ordinary column above it, and it was hidden either way until Alpine ran — so the content column painted across the full width and jumped aside when the columns arrived. Measured on a console shell at 0.1788 cumulative layout shift against a budget of 0.1, and it was the page's entire CLS. See App Shell.

  • The rail no longer flashes a horizontal scrollbar or slides its rows while it expands. Its scroller asked only for a vertical axis, and CSS promotes the other one to auto as soon as one axis scrolls — so the region was horizontally scrollable by omission. Separately, a module name sat in a line box taller than the glyph beside it, and every entry grew by the difference the moment its name appeared. See App Rail.

  • The script tag carries data-navigate-once, so a client-side navigation does not execute the bundle again. The bundle registers Alpine components and document listeners, which is a once-per-document job; without the attribute Livewire re-ran it on every hop and the listener set grew for as long as somebody navigated without a full reload. See Integration.

Documentation

  • The one diagnostic WireKit emits at error level is now documented as such. A missing package stylesheet makes every dialog and drawer render inside the page instead of over it — finished-looking and unusable — so the message is an error rather than a warning. The consequence worth knowing beforehand is that a console check gating on error goes red in that situation over an install step rather than a defect. See Console Output Baseline.
  • The marketing icon preset no longer puts a number on its own size. Its docblock claimed a count several times what the file declares: v2.37.0 moved the common semantic names into every base preset and the sentence stayed behind. A reader deciding whether to stack the extension at all was reading a figure that had been wrong for four minors — and the words it implied were missing had in fact become reachable from every preset. See Icon.
  • The shipped asset sizes match the files again. Four rows in the bundle catalog and three on the dependencies page had drifted; the readable stylesheet's row now names its property instead of a figure that moves whenever a rule gains a comment. See Dependencies.