What's new — September 2026
September 30
Visual Linker 0.2.0
Breaking (Vue):
<VisualLinker>no longer renders a wrapper<div class="vl-block">per block around a#block-<id>slot. It now wraps your own markup in its default slot, and blocks are discovered in it at any depth, inside any wrapper components. Migrate by moving the slot content into the default slot and marking each block element withv-vl-block="id"(ordata-vl-block="id"):vue<!-- 0.1.x --> <VisualLinker :blocks="blocks" :connections="connections"> <template v-for="b in blocks" #[`block-${b.id}`]="{}" :key="b.id"> <MyCard :data="b" /> </template> </VisualLinker> <!-- 0.2.0 --> <VisualLinker :connections="connections"> <MyCard v-for="b in blocks" :key="b.id" v-vl-block="b.id" :data="b" /> </VisualLinker>Breaking (Vue): the
blocksprop is now optional. An entry can register an element directly through a newelfield (a template ref, getter, element, or CSS selector), or — withoutel— only add config (ports, drag options) to a block already marked in the template.New (Vue):
v-vl-block/v-vl-portdirectives, exported asvVlBlock/vVlPort. A port attaches to the nearest block around it, or to the one named by itsblockoption.New (Vue): plain
data-vl-*attributes as a JavaScript-free way to mark blocks and ports (data-vl-block,data-vl-draggable,data-vl-drag-handle,data-vl-drag-bounds,data-vl-port,data-vl-port-block,data-vl-side,data-vl-offset,data-vl-anchor,data-vl-linker); the names are exported asVL_ATTR.New (Vue): live discovery — blocks and ports added, removed, or re-marked after mount (
v-if,v-for, third-party markup) are picked up automatically.New (Vue):
scopeprop —'container'(default) or'page', which links elements anywhere in the document and draws in aposition: fixedlayer teleported to<body>.New (Vue):
nameprop plus the directives'linkeroption /data-vl-linkerattribute, to assign an element to a specific<VisualLinker>;zIndexprop for the drawing layer. Other attributes passed to<VisualLinker>now land on its root element.New (Vue):
VisualLinkerPlugin—app.use()registers<VisualLinker>and both directives globally.VisualLinkerScope,BlockDirectiveOptions,BlockDirectiveValue,PortDirectiveOptions,PortDirectiveValue,RefFriendlyDragBoundsandRefFriendlyElementtypes are exported too.Changed (Vue): the drawing layer is rendered only client-side after mount, keeping the server render identical to the hydration pass.
New (Nuxt):
v-vl-block/v-vl-portare registered by a universal plugin — on the server too, so thedata-vl-*attributes are already in the server-rendered HTML.New (core):
MarkerConfig.arrow—trueor{ color?, gap? }(newMarkerArrowConfigtype) draws an arrowhead right before a circle/square/diamond marker, its tip stopping exactly on the shape's outer edge, outline included. A marker carrying an arrow always usesorient: 'auto'.Changed (core): while a connection is highlighted it's painted above its siblings, and other connections ending on the same point hide their marker there, so resting-size markers no longer overlap the highlighted one.
Fixed (core): a connection with an explicit
style.widthlost its hover/highlight width bump — the explicit inline width outranked the CSS rule. The bump is now applied inline too.Changed (core): dragging moves a block through the standalone CSS
translateproperty instead oftransform, so it composes with a transform the block already has instead of overwriting it.
September 26
InView 0.3.0
createRevealController's stagger delay now skips itself entirely underprefers-reduced-motion: reduce— the class/attribute toggle still happens normally, only the staggered timing is skipped.createElementTracker(and theuseElementViewport/useParallaxLayercomposables/hooks built on it, Vue and React) accepts arootelement to measureviewportProgress/distanceFromCenteragainst a scrollable container instead of the window — for a parallax layer or viewport tracker living insideoverflow: auto(a dashboard panel, a modal). The returnedrectitself stays window-relative either way.useElementVisibility's options are now reactive in both adapters. Vue:threshold/rootMargin/root/onceaccept a ref/getter —threshold/rootMargin/rootchanging re-subscribes for real,onceupdates live without tearing down the subscription. React:once/onEnter/onLeavenow update live across re-renders (previously frozen at the render that first created the subscription), and a fresh inlinethresholdarray literal every render no longer forces a needless re-subscribe.- New Vue composables:
useRevealController(createscreateRevealControlleron mount, destroys it on unmount),usePrefersReducedMotion(a reactiveRef<boolean>, unlike the staticprefersReducedMotion()),useStagger,useScrollTo,useScrollSpy. - New React hooks:
useReveal(the equivalent of Vue'sv-reveal— toggles a class/attribute automatically),useRevealController,usePrefersReducedMotion,useStagger,useScrollTo,useScrollSpy— same shape as the Vue composables above. - New in
@macrulez/inview-core:createScrollSpy(tracks which of a list of targets sits in an "active" band near the viewport's vertical center, for nav-highlight UIs) andscrollToElement(smooth-scrolls a target so an element lands at its edge, with a px offset). createRevealController's returned controller gainedobserve(el)/unobserve(el)(for elements outside theselectorscan) andrefresh(selector?)(a one-off scan with a different selector, on top of the existing no-argumentrefresh()). Per-elementdata-reveal-attributenow overridesactiveAttributefor one element, the same waydata-reveal-classalready did foractiveClass.- Nuxt's auto-import list now includes
useRevealController,usePrefersReducedMotion,useStagger,useScrollTo,useScrollSpy,createScrollSpy, andscrollToElement.
September 25
DevToolz 0.2.1
- New: the
full-checkcommand runs every other command in one sweep, each in its own safe read-only mode, and shows one summary table. The three commands that can write (strip-comments,console-strip,case-check) are always called as a preview. A bare run in a real terminal asks aboutstale-ts-ignore, the one slow command;--skipand--no-promptcontrol that. See Full Check. - Added to the programmatic API:
runFullCheck,renderFullCheckReportand their types.full-checkitself composes the other commands' ownrun*()functions, which the package root already exported.
DevToolz 0.2.0
- New:
unused-depsfindspackage.jsondependencies nothing imports, and "phantom" dependencies that are imported but never declared. See Dependency Graph. - New:
circular-importsfinds import cycles and shows each as its full chain; cycles made only ofimport typeare hidden unless--include-typesis given. See Dependency Graph. - New:
empty-catchfindscatchblocks that swallow the error, including ones that only log it. See Code Hygiene. - New:
todo-reportcollectsTODO/FIXME/HACKcomments with their text, with--tagsand a--maxratchet. See Code Hygiene. - New:
scripts-checkcross-checkspackage.jsonscripts against README/docs and CI workflows, andorphan-testsfinds test files whose source disappeared. See Consistency Checks. - New:
stale-ts-ignorefinds a@ts-ignorethat no longer suppresses anything, by comparing two real project-wide typechecks. See Stale @ts-ignore. - Added to the programmatic API: the
run*()andrender*Report()functions of the new commands. - Changed: the import graph and the real-comment detection moved out of single commands into shared utilities, now used by several;
readme-check'stsconfig.jsonloader was shared the same way.
DevToolz 0.1.0
- First release: one
devtoolzbinary with six commands. See Overview. strip-commentsandconsole-stripremove comments and leftoverconsole.log/debuggerstatements, with a preview by default,-yto write and--difffor a unified diff per file. See Code Cleanup.dead-exportsfinds named exports nothing imports, aware of a package's public entry points, re-export chains and workspaces. See Dead Exports.case-checkfinds imports whose case does not match the file on disk, with--fix. See Case Check.exports-doctorandreadme-checkverify a package from a consumer's side: declaredpackage.jsonpaths against the disk, and README code blocks against the package's own types. See Package Checks.
Network Dashboard 0.4.2
- Several
addMock/addMockToGroupexamples in the README and the Mocking guide omitted the requiredenabledfield — copy-pasted as written, the rule would have failed to typecheck, and if that were bypassed, the mock would have been silently skipped at runtime (addMock/addMockToGroupcheckrule.enabledbefore applying it). addMockToGroup's documented signature listedrule: Partial<MockRule>— the real type isOmit<MockRule, 'id'>, every field butidis still required.
Responsive Media 2.0.2
- The Vue integration guide's
useContainerStateexample calleduseTemplateRef('card')without an explicit type argument — Vue's own default (unknown) doesn't satisfyuseContainerState'sRef<Element | null>parameter, so the example as written never actually compiled. Now showsuseTemplateRef<HTMLDivElement>('card').
State Machine 0.2.7
- The README's code examples still imported the unscoped
vue-state-machinein five places instead of the real published name@macrulez/vue-state-machine— a leftover from before the package was moved under the scope. - The Wizards guide's
CheckoutCtxexample declared it withinterface— TypeScript doesn't give aninterfacethe implicit index signatureCtx(Record<string, unknown>) needs, soWizardStep<CheckoutCtx>never actually type-checked as written. Switched to atypealias, matching the pattern already used elsewhere in the same doc.
September 24
Color Value Tools 1.2.2
- New subpath imports by function group:
color-value-tools/parse,/convert,/manipulate,/palette,/a11yand/cache. They work with bothimportandrequireand ship their own TypeScript types. Importing from the package root works exactly as before. - ESM consumers now get ESM type declarations; previously the ESM build used the CommonJS
.d.tsfiles. - The package is marked
sideEffects: false, so bundlers can drop unused code more reliably. - The
cvtCLI now uses the package's own build instead of shipping a second copy of the library. Commands and output are unchanged.
Image Kit 1.2.0
sourcesentries can now carry their ownwidth/heightfor art-direction breakpoints whose crop has a different aspect ratio than the root image — either as{ src, width, height }or by passing a build-timeImageMetaobject directly (e.g. from a?vikimport). Give a breakpoint its own dimensions and<VImage>reserves the placeholder — and the blurhash preview — at that breakpoint's own proportions instead of always falling back to the root image's, so switching breakpoints no longer causes a layout shift once the real photo loads. Entries withoutwidth/heightkeep working exactly as before.- A
sourceskey that doesn't match any registered breakpoint now warns in development, naming the key and the breakpoints that are available, instead of silently doing nothing.
Image Kit 1.1.8
<VImage>no longer forcesdisplay/box-sizing/object-fitas inline styles when it doesn't need to — inline styles always beat a class your app applies to the same element, regardless of specificity. An explicitfitprop is still applied inline (guaranteed to win). Left unset, theobject-fit: coverdefault now comes from a plain, overridable CSS class — applied only when the image box is actually constrained (layout"fill"/"fixed", or bothwidthandheightgiven), and omitted otherwise since it has no effect without a constrained box. The same applies to the basedisplay/sizing styles —width: 100%; height: autois now only applied when bothwidthandheightare given (there's no intrinsic ratio to preserve otherwise), so a bare<VImage>sized purely through your ownmax-height/max-widthCSS keeps its natural aspect ratio instead of being stretched to the container's full width.- Fixed: the package's stylesheet (the shimmer placeholder's animation, and now the classes above) was never reachable via
import '@macrulez/vue-image-kit/style.css'— it wasn't declared in the package'sexports, soplaceholderMode="shimmer"shipped non-functional everywhere. The Nuxt module now registers the stylesheet automatically. - Fixed: 1.1.7's wrapper removal caused
<VImage>to trigger a Vue hydration mismatch warning on every server-rendered page — the check it used to decide what to render couldn't tell "the server" from "the client's very first render during hydration", so the two never actually matched. It's now hydration-safe.
InView 0.2.3
- Fixed:
createRevealController's stagger delay (--reveal-delay/ the inlinetransition-delayit sets) used to stay on the element forever after it appeared — so any other transition on that same element, like a hover effect on a.reveallink, silently inherited the same delay too. The delay is now automatically removed once the reveal-in transition actually finishes (or, if it never runs —prefers-reduced-motion, no matching CSStransition— after a short fallback timer), so later transitions on the element are unaffected. No configuration needed, this is just how it behaves now.
September 23
Image Kit 1.1.7
<VImage>no longer renders inside a wrapper<span>. Every earlier version wrapped the real<img>(and, while loading, whichever blurhash<canvas>/LQIP-ThumbHash<img>/solid-color or shimmer<span>placeholder was active) in a persistent positioning<span>, which made the component awkward to drop into markup that expects to own the element it's styling directly. Every placeholder kind is now painted as a CSS background directly on the same element that goes on to show the real photo — an idle placeholder element before loading starts, swapped outright (not nested) for the real<img>/<picture>once it does.class/style/data-*/other attributes now land on that one real element. The smooth "blur visible through a fading-in sharp photo" crossfade isn't possible anymore — swapping is an instant cut; the newfadeInprop (below) is a different, simpler effect, not a replacement for the old one.<VImage>'s newfadeInprop (defaultfalse) opts into a ~0.3s opacity fade-in on mount.
September 12
Color Value Tools 1.2.1
isReadableOnBackground()'swcagLevelnow uses the same effective background color asminContrastRatio/readablefor'semi-transparent'/'gradient'backgrounds, instead of always'#ffffff'.
Command Palette 0.2.9
bindShortcutsnow binds hotkeys for nestedsubCommands too, not just top-level commands.- The hotkey fallback executor (
runFallback, used with no<CommandPalette>mounted) now correctly openspage-only commands and handlesconfirm/frecency tracking like the realexecuteCommand. CommandItem's match highlighting now reuses the diacritic-awareFuzzySearchscorer instead of a separate, less accurate implementation.- The Nuxt module now registers the package's components via
addComponentand auto-imports every composable/factory, not just 3 of them. isLoadinginCommandPalette.vueis now a ref-count across concurrent search pipelines, instead of one shared boolean that could clear prematurely.- Async result merging now replaces an already-merged sync result with a better-scoring async result of the same id, instead of "first-registered wins".
PaletteProvider(testing.ts) now also providesPALETTE_REGISTRY_KEY— named-instance lookups (useCommandPalette('name')) now resolve correctly under it.- Unified the global hotkey toggle (
installPalette) anduseCommandPalette()'s owntoggle()/open()/close()onto one open/close implementation (includinghistoryclearing). - Function-valued Nuxt module options (
vCommandPalette:onOpen,onError,search,onSearch, etc.) are no longer serialized into the clientruntimeConfig.public— only the serializable subset crosses that boundary.
CSS Magic Gradient 1.3.1
- Added reactive
useMonochromaticGradient/useHueWheelGradienthooks to bothcss-magic-gradient/vueandcss-magic-gradient/react— previously these two generators were only available as plain functions, with no reactive wrapper, unlike the package's other 8 generators.
Error Boundary Kit 0.3.5
<AsyncBoundary>is now auto-registered as a global component by the Nuxt module, alongside<ErrorBoundary>.createHttpReporternow returns a cleanup function to remove itspagehidelistener.- The Nuxt module's
autoImportslist now covers every composable/ factory in the package, not just 3 of them.
Feature Toggles 0.2.0
- Added
'live'to theFlagSourcetype for SSE/WebSocket-pushed flag updates. <Feature>with neithernamenorgroupnow logs a dev-mode warning instead of silently rendering nothing.- The Nuxt module now accepts
loader/rulesin its own config and auto-imports the package's composables.
Form Schema 0.2.8
@macrulez/nuxt-vue-form-schemais now either published for real or no longer referenced as installable.- An async
options()function on a field no longer re-runs on every form value change — only when its ownoptionsDepschange. isValidnow accounts for a still-pending async validator, instead of onlysubmit().- The default
persistKeyis no longer a plain comma-joined field-name list — two unrelated forms with identically-named fields no longer silently share persisted storage. remove/move/swaponuseFieldArraynow correctly renumberform.errors/form.touched.- The Vue DevTools panel is now wired up automatically by the plugin's
install()— no manualinstallFormDevtools(app)call needed.
i18n Kit 0.4.12
I18nKitConfig,LocaleConfig, andLocaleMetaare now exported fromvue-i18n-kit/config, so they can type-check a hand-writteni18n-kit.config.json.- Removed dead code
src/cli/commands/init.ts(runInit) — unused by the CLI and by any test, and using a plural syntax incompatible with the package's own ICU engine.
Image Kit 1.1.6
v-lazy-imgnow shares the same pooledIntersectionObserverevery other lazy-loading path uses, instead of creating its own per element.- Unset
layoutnow gets the same auto-sizesheuristic aslayout="responsive". - Blurhash and a LQIP/thumbhash placeholder can no longer mount simultaneously when both props are supplied — restored a single either/or precedence.
InView 0.2.2
- Added the missing
<InView>component andsetViewportDefaults/viewportDefaultsregistration to the Nuxt module (previously only composables/utilities/v-revealwere wired up).
Network Dashboard 0.4.1
- Fixed the package's own
npm run type-check— broadened the*.vuemodule shim to also declare<script setup>'s named type exports (e.g.NetworkDebuggerProps). - Cleaned up the dead/divergent
useHotkey.ts/useLogFilter.tscomposables that duplicatedNetworkDebugger.vue's own inline logic. - Closed a dormant cross-test
localStorageleak from a missing mock reset in thepersistToStoragetests. - Fixed subpath import examples in JSDoc comments (
devtools.ts,adapters/sentry.ts,adapters/opentelemetry.ts) — all three symbols are only reachable from the package root.
OS Detect 2.2.1
detectIsiOS()(deprecated alias) now logs its deprecation warning once instead of on every call.useIsWindows11()(Vue and React) no longer calls its setter/assigns its ref after the component has unmounted.detectIsWindows11()is now memoized like every other detector, withresetDetectionCache()support.- Synced
package-lock.json's version withpackage.json.
Responsive Media 2.0.1
isAbove(key)now correctly returnsfalsefor an unrecognized breakpoint key — fixed in the core, Vue, and React implementations.- Unified the two independent
isSSR()implementations into one, stricter check (windowandwindow.matchMediaboth present). - Vue's
useBreakpoints()now honorsinject()/DI, matchinguseResponsive(). - Vue's
useMediaQuery()can no longer leak itsmatchMedialistener when called outside an active component — the composable now always returns a stop function. - React's
useContainerState()now recreates itsResizeObserverifref.currentwasnullon the first effect run (e.g. an element behind a later-mounted conditional/portal). hydrate(initialState)no longer silently drops keys missing from the live state — it now warns.- Added baseline automated test coverage for the Vue and React adapters (previously only the framework-agnostic core was tested).
Rest Pipeline JS 2.1.5
- Reconciled config-based client caching between
useRestClientVue(cached) anduseRestClientReact(uncached) into one documented contract. - Clarified and documented WebSocket stage pass/fail semantics — no longer decided by
close.wasCleanalone, ignoring a visibleonError.
State Machine 0.2.6
MachineStore.register()now warns in dev mode on an id collision instead of silently overwriting the prior entry.useMachine()now auto-unregisters from theMachineStore/DevTools registry when its owning component unmounts.useSharedMachine(config, options)now warns in dev mode when a later call for the same id passes different options (includingpersist).
Storage Kit 0.2.7
useStorage()now warns in dev mode when a second caller for an already-livekey+targetpasses different options (previously silently ignored).- Added a dev-mode warning when both
throttleanddebounceare set on the same call. - Added a dev-mode warning when
httpOnlyis set on the base (client-only)useCookie()outside the Nuxt SSR context. compress()now surfaces a warning/error the same wayencrypt()/sign()already do, instead of silently degrading to pass-through.- React's
useStoragenow reacts tokey/targetchanging across re-renders, matching the Vue version.
Toast Kit 1.1.1
ToastContainer'sexpandprop is now wired up (was declared but never read).ToastItem.isGroupednow reflects real grouping state instead of always beingfalse.toast.update()/queue.update()now restarts the auto-dismiss timer whendurationchanges.- Synced
CHANGELOG.mdwith the currentpackage.jsonversion.
Virtual Scroller Kit 0.3.1
- Added
containerRole/itemRoleoverride props toVirtualGrid, matchingVirtualList/VirtualTree/VirtualSelect. - Added test coverage for
InfiniteLoader.vue(threshold logic, load direction, concurrent-load guard, scroll-position preservation on prepend loads). - Updated
engines.nodeinpackage.jsonto match the toolchain's real minimum (Node 20/22).
Worker Kit 0.2.5
run()/map()oncreateWorkerPool/useWorkerPoolno longer discardctx.reportProgress()/ctx.reportChunk()— progress and chunks are now wired throughWorkerPool.useWorker()now exposes an explicitterminate()method.- A crashed worker (
Worker.onerror) is now recreated on the nextrun()instead of reusing the broken instance. - With
streaming: false, callingctx.reportChunk()now logs a dev-mode warning instead of silently dropping the chunk. - Removed the stale
"nuxt"keyword frompackage.json(no Nuxt module exists in this package). WorkerComputedResult's fields are now wrapped in Vue'sreadonly(), enforcing thereadonlytyping at runtime too.RetryStrategyOptions/StreamingOptionsare now used as the real parameter types forUseWorkerOptions/UseSharedWorkerOptionsinstead of being redeclared inline.