Skip to content

v2.33.0

Choose a tag to compare

@pushery pushery released this 19 Aug 11:40
· 30 commits to main since this release
916b6ee

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 --audit tells 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-serve could 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_component now 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, saw config('wirekit.components.button.intent', 'primary') as the default and had to guess what may be passed, and — worse — was never told that
    card.body exists, 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 a config(...) 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, and ComponentRegistry::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-area gained fade="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. auto masks 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-size token.

  • wirekit:doctor names 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 new WireKit::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:props gained --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 @source glob 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 use flex or gap-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 @wirekitStyles the 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 unconfigured sans or mono is 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.fallbacks example 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:doctor told 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_BR and pt-BR are
    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.

  • list reported 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 form list is
    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,
    menubar or
    navigation-menu menu 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-menu and
    combobox had 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-audit itself 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,
    undefined and void, 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 what WireKit::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 --tier examples 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 words gap-wk,
    design-tokens, ladder and rung appeared zero times on the row, stack and grid pages, so a
    developer typing gap="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, subComponents and extractAwareProps were 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_hint was 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() and isValid() are documented together now, with isDefault() called
    out separately because it is the one a picker gets wrong: default is 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() and WireKit::prefix() are documented — the first in the
    integration guide's nonce section, with
    its resolution order and the fact that null means "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 and wirekit is 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.