v2.33.0
Minor — this release is about being told what you actually have. wirekit:doctor names every
personalized class block your application owns, wirekit:icons --audit separates the icon names
under contract from the ones that merely work today, the MCP server hands an assistant real worked
examples and the full component signature instead of a name and a category, and a scroll area fades
only the edges its content really continues past.
Added
-
wirekit:icons --audittells you which of YOUR icon
names are under contract.<x-wirekit::icon>renders any name your icon set knows, so a glyph
name works — and looks exactly like a declared alias right up until somebody switches preset, at
which point every one of them breaks at once. The audit reads your views and separates the two,
with the file and line of each fall-through. It never calls a glyph name an error (some glyphs
have no alias and never will) and never suggests a replacement (checked across ten such pairs,
ten pointed at a different character). Names bound at runtime are counted separately rather than
quietly dropped, and a run that finds no icon usage at all exits non-zero — "nothing was measured"
and "nothing is wrong" are different answers. -
The MCP server gained
get_component_examples— worked examples instead of assembled markup.
php artisan wirekit:mcp-servecould tell an editor what
props a component accepts; it could not show one being used. A prop list says what is allowed, and
an assistant filling one in guesses at the composition — which sub-component wraps which, which
props are set together, what the canonical shape actually is. The new tool answers that from real,
reviewed usage: 439 examples covering every documented component, and a sub-component (card.body)
resolves to the page where it is shown inside its parent. Ask for it before writing markup.
Documented in the AI tooling guide. -
get_componentnow answers with the whole component, not a summary of it. The MCP server
described a component as a name, a category, a description and three fields per prop. An assistant
reading that could not tell an enum from free text, sawconfig('wirekit.components.button.intent', 'primary')as the default and had to guess what may be passed, and — worse — was never told that
card.bodyexists, which is the one composition rule the shipped guidance spends a paragraph on.
It now returns the same picture the JSON manifest carries: the documentation URL, whether the
component is anonymous or class-based, every declared slot with whether it is required, every
sub-component with its own props, and the full prop signature including type hints, the resolved
default behind aconfig(...)call, and the example values the docblock names. A test compares
the two surfaces field by field, in both directions, so one can no longer learn something the
other does not. Documented in the AI tooling guide. -
Three registry helpers became public API, because the manifest and the MCP server were each
deriving the same answers privately and had begun to disagree:ComponentRegistry::slotsOf(…)
returns a component's declared slots with their required flag,ComponentRegistry::describeSubComponentsOf(…)
returns its sub-components with their props, andComponentRegistry::existingBladeFilePath(…)
resolves a component's template — or null when it has none, which is the answer the
path-returning companion cannot give.The examples are extracted when the package is built rather than read at runtime, because the
documentation is not part of what gets installed — a server that read it would answer correctly in
WireKit's own repository and "no examples" in yours. -
scroll-areagainedfade="auto"— an edge
fade that measures before it masks. The named edges (both,start,end) are unconditional
CSS, which is what makes them free and also what limits them: they fade the top edge while the
reader is already at the top, the bottom edge at the bottom, and both edges on an area whose
content fits and cannot scroll at all — taking ink off text that is entirely visible, to signal
something that is not true.automasks only an edge the content continues past, and follows
content that arrives later, which is the case worth having it for: a transcript appending a
message, a list a search filters down, a panel that opens. Nothing to call, nothing to refresh.
It is the one value that needs JavaScript, and it fails toward no mask at all rather than the
wrong one — a missing hint instead of dissolved text. The named edges are untouched and stay pure
CSS, so nothing that exists today changes, and the depth is still the--fade-wk-sizetoken. -
wirekit:doctornames every personalized block that
replaces the shipped one.
WireKit::personalize()takes two value shapes per
block, and they differ in a consequence nothing reported: a finished class string REPLACES the
block, while a closure receiving the vendor default extends it. A replacement is a valid choice —
it also ends the flow of later WireKit changes to that block, permanently and without a word, so
the personalization keeps looking like a decision somebody made long after it has stopped
inheriting improvements. The check reports replacements as a warning with the block names and
offers the closure form for the case where only a delta was wanted. It stays silent when every
block extends. A newWireKit::personalizedComponents()returns the names of the personalized
components; the map could be read per component but never enumerated, and a diagnostic cannot
guess names it has no way to list. -
wirekit:doctor:propsgained--require-in-scope.
A run that scans real templates and finds none of them using a WireKit component has two honest
readings, and which one is right depends on the application rather than on the linter. If you do
not use WireKit in that tree, nothing in scope is correct and the default still succeeds. If you
use it everywhere, the same result means the walk found the wrong tree — a second view path, a
renamed directory, an argument pointing somewhere empty — and a green run is the last thing you
want. The flag is how you say which application you are. Reported by a developer whose only handle
on that state was matching the success sentence in a shell script, which a reword would have
deleted silently.
Fixed
-
The tab bar's active indicator was missing from the compiled CSS. A tab bar's appearance
moved into PHP in 2.31.0 — a good refactor, and one Tailwind's@sourceglob never looks at, so
six classes stopped compiling. They were not decoration: they are the active-tab indicator and
the margins that pull it onto the container edge. The bar rendered, the tabs worked, the ARIA was
correct, and the selected tab was simply not marked. Reported from a project that attributes its
built stylesheet byte for byte — 123702 → 123169 bytes, six selectors gone and none added. Fixed
through the safelist mechanism that already exists for this class of bug, listing all 48 emitted
classes rather than only the six that went missing: the other 42 survive today because some
unrelated view happens to useflexorgap-1, which is a coincidence and not a guarantee. -
<x-wirekit::fonts>overwrote the shipped font
tokens with weaker ones. The component wrote all three--font-wk-*variables unconditionally,
standing in a hardcoded stack for a category nobody had configured — and those stand-ins are
shorter than what the package ships. Both declarations sit unlayered at equal specificity, so
document order decided it, and placed after@wirekitStylesthe monospace stack silently lost two
families. Nothing threw and the markup was identical either way; it showed only to a reader who
had those fonts installed. An unconfiguredsansormonois now simply not declared, so the
stylesheet's value stands from any position. Serif is deliberately still written, because the
stylesheet does not declare it and omitting it would drop every serif surface to the browser
default. -
The
fonts.fallbacksexample gave a real family another font's numbers. The configuration
stub and the fonts page both showed a named family
with measurements that belong to a different one — directly below a line reading "measure the four
values, do not estimate them". A developer whose font really was that family read the block as
already measured and pasted it. Both examples now use a placeholder family with blank
placeholders: a blank cannot be copied, a plausible number can. -
wirekit:doctortold developers to delete configuration that was working. The config-drift
check compared key names against the shipped stub and reported anything the stub does not carry as
an option "this version no longer offers". Reported from a project where ten keys were named and
all ten were wrong, in three shapes — keys whose names belong to the developer rather than to the
stub, a feature whose stub value is an empty array so no correct use could ever match, and leaves
sitting under a branch the stub does carry. Developer-keyed nodes are now exempt, a path that is a
prefix of a stub key is not an orphan, and the wording no longer asserts that nothing reads them:
a diff is evidence, not a verdict. The list also prints in full, because the truncation hid half
of a finding whose whole point was which keys were named. -
An underscore-spelled regional locale resolved to the wrong variety.
pt_BRandpt-BRare
one locale wearing two separators, but only the base-language half of that was handled. The
underscore spelling never reached the regional catalog this package ships: it missed, the base
fallback answered, and a Brazilian-Portuguese application quietly rendered European Portuguese.
Nothing threw — the strings were all present, just from the wrong catalog. -
The component manifest said nothing about
glass. Of the whole catalog, exactly one component
carries no props, no slots and no sub-components, and its emptiness is real. In a manifest that is
indistinguishable from a component whose props could not be parsed — and the wrong reading is the
expensive one, because a tool that assumes a parse failure will invent an API. Its description now
says so, and a guard requires any component with nothing to declare to declare that. -
listreported that it accepts no content. Every machine-readable surface — the JSON
manifest, the project-root schema file, and every tool fed by them — listed the component with an
empty slot array while its template renders{{ $slot }}on its last line. A developer asking
the manifest how to use it was told to write an empty tag. The cause was a second Blade-path
resolver that knew the flat and dotted filenames but not the directory-index formlistis
written in, so the file was never found and "no template" read as "no slots" — indistinguishable
from the components that genuinely have none. Both surfaces resolve through one path now, and a
test fails whenever a component that renders a default slot fails to report one. -
Two siblings of the same overlay no longer stand open at once. Opening a second
popover,
dropdown,
hover-card,
menubaror
navigation-menumenu on the same page left
the first one open behind it, and the two panels overlapped. Nothing reported it — no console
error, no changed markup — because the only symptom is what a reader sees.context-menuand
comboboxhad each solved it separately; all seven now share one mechanism, so the next overlay
inherits it instead of copying it. Opening a dropdown still does not close a popover: the
coordination is per component family, which is the behavior that existed before and is not a
question a patch release should answer differently. -
The CSP advice about method names was far wider than the rule it described, and the extra
width cost real renames. Two pages and
wirekit:csp-audititself said that a Livewire method
"whose name is a JavaScript keyword" needs index access —$wire['delete'](...)instead of
$wire.delete(...). Measured against the parser that decides it, that is true of ten names and
false of the forty-two other reserved and future-reserved words, because a reserved word after a
dot has been an ordinary property name since ES5. A developer auditing their own component
against the old sentence renames public action names —for,class,return— that were never
affected, and every one of those renames is reachable from templates and tests. All three places
now print the set itself:delete,false,in,instanceof,new,null,true,typeof,
undefinedandvoid, with a named counter-example so the list reads as complete rather than as
a sample. The set is no longer written by hand anywhere — it is checked against the tokenizer's
own table on every test run, so a future change to that table fails the build instead of leaving
three pages quietly wrong.
Documentation
-
Two PHP entry points that were only findable in the source are now on a page.
WireKit::avatarPaletteFor(...)returns the same background/foreground pair
<x-wirekit::avatar from-initials>derives, so a custom chip can match an avatar without rendering
one.WireKit::defaultsFor(...)reads back whatWireKit::defaults([...])registered — with the
distinction stated on the page, because it reports the runtime record rather than the value in
effect. -
Four tables across three pages rendered as raw text and now render as tables. A blank line, a
callout and a paragraph had each been placed inside a table, and one font-size table carried no
header row at all. Markdown ends a table at the first interruption rather than resuming it
afterwards, so every row below the break was published as pipe-separated body text. Affected the
bundles table on the dependencies page, the App Shell prop table, and the motion and font-size
token tables. -
wirekit:verify --tierexamples corrected. The commented check ranges beside the two--tier
examples still described the numbering from before a check was added, and the environment-tier
comment pointed at a package-tier check. -
The gap scale is now reachable from the components that use it.
--gap-wk-*and
--space-wk-*do not run on the same ladder, and the
design-token page has said so since 2.28 with
three guards keeping the table honest. It was still reported twice from two applications eight
days apart, and the second report was measured against a version that already carried the table.
That is a placement problem rather than a documentation one: measured, the wordsgap-wk,
design-tokens,ladderandrungappeared zero times on the row, stack and grid pages, so a
developer typinggap="lg"had no path to the paragraph that prevents the mistake — which also
had no heading, so it was neither linkable nor in the page's contents. It has one now, and the
five components that let a developer name a rung link to it:
row,
stack,
grid,
bento-grid and
feature-grid. -
The customization page no longer says nothing warns
you. Its section on adjusting a block rather than replacing it explained that taking ownership
silently stops later improvements from reaching it, and closed with "nothing warns you, because
nothing is broken". The doctor check in this release is that warning, so the sentence became
false in the same release that made it obsolete. It now names the check. -
The PHP discovery surface is documented where it claims to be. The
ComponentRegistry page opens by calling
itself the canonical surface for discovering every component, and documented five of its thirteen
entry points —subComponentsOf,tag,tagAlias,resolve,componentClass,
isSubComponent,subComponentsandextractAwarePropswere all shipped and described nowhere.
All of them are there now, with the three this release adds. Two claims on the page were also
wrong:type_hintwas said to be always null where fifteen props carry one, and the prop-record
table listed five fields where the record has six. -
The theme-preset registry had only its write side on a page.
ThemePresetRegistry::register()was documented; the
four reads that make it useful were not — which is exactly the set a theme picker needs.
all(),keys(),get()andisValid()are documented together now, withisDefault()called
out separately because it is the one a picker gets wrong:defaultis not a preset with variables,
it is the instruction to remove the block, and treating it as a normal preset writes an empty one. -
WireKit::cspNonce()andWireKit::prefix()are documented — the first in the
integration guide's nonce section, with
its resolution order and the fact thatnullmeans "no policy" rather than a failed lookup; the
second in Getting Started, where code that builds a
tag name should ask rather than assume, because the prefix is a setting andwirekitis only its
default. -
Localization no longer reads as base-language only.
The page described the shipped catalogs without saying that a regional variety is a catalog of
its own, which is the half a developer needs before choosing a locale string.