WireKit v2.34.0
Minor release. It adds the pieces an application shell was missing — a module rail, a column head, and the switcher that says what the page is about — and fixes a set of defects across charts, overlays, pagination and the CLI.
Added
app-rail— the full-height module rail, withapp-rail.item,app-rail.groupandapp-rail.brand. The narrow column of icons an application puts its top-level areas in. It has three label modes — a tooltip beside the icon, a caption under it, or the name inline once the rail is wide — and it never truncates: a rail wide enough for captions wraps them instead, because a navigation whose labels are cut off is a navigation you have to guess at. The brand row centers while the rail is an icon strip and aligns to the column's spine once it is wide, and the workspace name is uncovered as the rail widens rather than appearing in the first frame of the animation. A current-module marker (edge) sits inside the row it marks, and a counter badge reads rail-specific colors so it stays visible on a toned column. The collapse toggle sits at the bottom, in the footer block, and takes no navigation row of its own when the rail is expanded.shell-bar— the aligned column head that draws an app shell's top rule. Every column in a shell draws that rule at the same height, from the same component, off the same token, which is what makes one line across all the columns. It carries three clusters: a pinnedstart, a scrolling middle, and an end. Thestartslot exists because the middle one scrolls — a hamburger or a back arrow placed there scrolls away with the tabs the moment the bar overflows, which on a phone is immediately. The scrolling cluster draws no scrollbar of its own, since the bar's bottom edge is the shell's rule and a track drawn there is a second, shorter line a few pixels under the real one; it still scrolls by touch, wheel and Tab.app-shelltakespanelandtone.panelinsets the content into a rounded sheet that stands on the chrome — inset by the same amount on all four sides, with the shell's rule reaching it rather than stopping short at the seam.tonecolors the chrome around it. A chrome column standing beside an inset panel draws no edge of its own, so the two do not sit a hairline apart.scope-switcher— the control that changes what the page is about. Workspace, project, tenant, environment: the thing every application has and everyone builds again, usually as a dropdown, which makes it a menu of commands rather than a list with a current member. It is a listbox with search, groups, status and an optional create action, it sits where the answer already is — the first crumb of a breadcrumb — and it tells a screen reader which entry is the current one, which a menu structurally cannot. The search tolerates a typo: each word is tried as a substring, then as a subsequence, then within one edit of a part of the entry — with a swapped pair of letters counted as one edit rather than two, because that is how a name typed from memory usually comes out wrong.popovertakeslabelandpadded. The panel is arole="dialog", solabelis what a screen reader announces on entry — the default was the word "Popover", identical for every popover on a page.padded="false"hands the whole surface to the caller, which is what a panel with its own header, scroll region and footer needs: those have to reach the panel's edges.- Type-ahead in
dropdownmenus. Typing a letter jumps to the next item starting with it; keep typing to narrow, or press the same key again to cycle through everything sharing that letter. The buffer clears after half a second. This was documented for a long time and never implemented — the line was eventually removed from the docs rather than the behavior added. - A
data-tablecolumn may name its own status words.intentsmaps a cell value tosuccess/warning/danger/neutral, so a status the built-in English list never had — a domain term, another language — is no longer stuck on neutral. The built-in list is now documented in full rather than as an excerpt. wirekit:verify--fail-on=error|warning|none. The command exited 0 however many warnings it printed, so it could not gate a pipeline on the question it answers best.warningmakes them a failure; the default is unchanged.- Seven icon aliases —
more,more-vertical,arrows-left-right,hash,shield-warning,prohibit,scan— including the first word for the overflow menu. Each has a genuine matching glyph in every preset WireKit ships, which is the standing admission test for the vocabulary. --space-wk-nav-gap— the gap between rows in a navigation column, read by both the rail and the sidebar.--color-wk-rail-badgeand--color-wk-rail-badge-fg— the counter dot and the digits on it, as rail roles, so they invert with a toned column.--wk-rail-item-aspect— hold a rail's icon-only rows to a square.data-wk-rail-brand-label— mark anything in the rail'sbrandslot that is a label, and it appears only while the rail is wide enough to hold it.
Fixed
- The ApexCharts adapter stopped warning about itself. It has two entry paths — register
eagerly when Alpine is already present, register again on
alpine:init— and in a Livewire application both always run, because Livewire assignswindow.Alpinelong before it starts it. The guard counted registrations, so every page of every Livewire app printed "the adapter is on the page more than once" and sent the developer looking for a second copy that did not exist, including on pages with no chart. It counts script evaluations now, which is what that sentence actually means. - The self-contained Alpine bundle no longer leaves the page inert when another Alpine is
present. It detected the other one and skipped every component registration, so the
Alpine that was actually walking the page had never heard of any of them: 31 console errors,
wirekitDropdown is not definedamong them, and a page that renders perfectly and does nothing. It registers on the Alpine that is running now and starts one only when there is none — and says so, because the CSP guarantee belongs to whichever Alpine evaluates the expressions. The same branch registered the collapse plugin on the wrong instance, so four components lost their animation silently. app-shelltells you when it builds a drawer nothing can open. Below thelgbreakpoint the shell moves asidebarorrailinto an off-canvas panel — a decision the shell makes, not one you ask for — and the only thing that brings it back is a<x-wirekit::sidebar.toggle>. A composition without one has no navigation on a phone, and nothing said so. It now writes that to your log whenAPP_DEBUGis on..wirekit-install.logstops growing without bound. It records the prior content of every file an install touched sowirekit:install --rollbackcan put it back — and a reinstall touches the published asset bundles, so the second install and every one after it wrote roughly ten megabytes into your project root, forever. Nothing warned, because an append is not an error. The five newest sessions are kept;--rollbackonly ever replays the newest, and it read the whole file to find it — so on a log that had been allowed to grow, the command that undoes a bad install was the one that ran out of memory.popoverreturns focus to its trigger when it closes. Escape left focus on<body>, which drops a keyboard user out of the page they were in — WCAG 2.4.3.- The sidebar reads one vertical rhythm. Its
first row sat 17px below the rule and its rows 8px apart, and the 17px was not a spacing
anybody chose — it was the column's inter-zone gap, plus a 1px scroll-shadow sentinel, plus
one more gap that the sentinel took part in. It reads
--space-wk-nav-gapnow, the same token the rail does, so two navigation columns side by side agree. calloutrenders a<div>rather than an<aside>. An<aside>is acomplementarylandmark, and a shell already has one in its sidebar, so any screen showing a callout carried two same-role landmarks with no distinguishing name — an accessibility failure that gets reported against the sidebar. A callout is a note in the flow of the text, not a self-contained section. If you styled callouts by element selector, target the class instead.paginationrenders aCursorPaginatorinstead of throwing. Its only guard asked "is there more than one page", which both paginator kinds answer — so a cursor paginator passed it and then reached methods it does not have. Sincefullis the default, the ordinary case failed. It now rendersmini(previous/next), which is the whole of what cursor pagination can drive, and says so in the log whenAPP_DEBUGis on.wirekit:icons--auditreads icon names passed as props, not only<x-wirekit::icon>tags. Both resolve the same way, so both carry the same risk on a preset switch; a project that names its icons in props was getting a clean result over a fraction of its surface. The set of components that take an icon name is derived from the components themselves.- An optimistic control inside a menu never sent its request. The layer looked for its
Livewire component among the direct children of
<body>, which stopped being where teleported panels land. With no component it silently fell back to a stub, installed no interceptor, and sat showing an unconfirmed value forever. Only one component could reach that path, so it looked like a single broken control rather than a broken mechanism.
Changed
- The sidebar draws no edge of its own while it stands on an app shell's chrome beside an inset content panel — the panel's own margin already separates the two, and both drawing an edge put a doubled hairline there.