Skip to content

What's new — September 2026 ​

Subscribe (Atom)

September 30 ​

Visual Linker 0.2.0 ​

Package version history

  • 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 with v-vl-block="id" (or data-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 blocks prop is now optional. An entry can register an element directly through a new el field (a template ref, getter, element, or CSS selector), or — without el — only add config (ports, drag options) to a block already marked in the template.

  • New (Vue): v-vl-block / v-vl-port directives, exported as vVlBlock / vVlPort. A port attaches to the nearest block around it, or to the one named by its block option.

  • 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 as VL_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): scope prop — 'container' (default) or 'page', which links elements anywhere in the document and draws in a position: fixed layer teleported to <body>.

  • New (Vue): name prop plus the directives' linker option / data-vl-linker attribute, to assign an element to a specific <VisualLinker>; zIndex prop 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, RefFriendlyDragBounds and RefFriendlyElement types 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-port are registered by a universal plugin — on the server too, so the data-vl-* attributes are already in the server-rendered HTML.

  • New (core): MarkerConfig.arrow — true or { color?, gap? } (new MarkerArrowConfig type) 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 uses orient: '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.width lost 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 translate property instead of transform, so it composes with a transform the block already has instead of overwriting it.

September 26 ​

InView 0.3.0 ​

Package version history

  • createRevealController's stagger delay now skips itself entirely under prefers-reduced-motion: reduce — the class/attribute toggle still happens normally, only the staggered timing is skipped.
  • createElementTracker (and the useElementViewport/useParallaxLayer composables/hooks built on it, Vue and React) accepts a root element to measure viewportProgress/distanceFromCenter against a scrollable container instead of the window — for a parallax layer or viewport tracker living inside overflow: auto (a dashboard panel, a modal). The returned rect itself stays window-relative either way.
  • useElementVisibility's options are now reactive in both adapters. Vue: threshold/rootMargin/root/once accept a ref/getter — threshold/rootMargin/root changing re-subscribes for real, once updates live without tearing down the subscription. React:once/onEnter/onLeave now update live across re-renders (previously frozen at the render that first created the subscription), and a fresh inline threshold array literal every render no longer forces a needless re-subscribe.
  • New Vue composables: useRevealController (creates createRevealController on mount, destroys it on unmount), usePrefersReducedMotion (a reactive Ref<boolean>, unlike the static prefersReducedMotion()), useStagger, useScrollTo, useScrollSpy.
  • New React hooks: useReveal (the equivalent of Vue's v-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) and scrollToElement (smooth-scrolls a target so an element lands at its edge, with a px offset).
  • createRevealController's returned controller gained observe(el)/ unobserve(el) (for elements outside the selector scan) and refresh(selector?) (a one-off scan with a different selector, on top of the existing no-argument refresh()). Per-element data-reveal-attribute now overrides activeAttribute for one element, the same way data-reveal-class already did for activeClass.
  • Nuxt's auto-import list now includes useRevealController, usePrefersReducedMotion, useStagger, useScrollTo, useScrollSpy, createScrollSpy, and scrollToElement.

September 25 ​

DevToolz 0.2.1 ​

Package version history

  • New: the full-check command 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 about stale-ts-ignore, the one slow command; --skip and --no-prompt control that. See Full Check.
  • Added to the programmatic API: runFullCheck, renderFullCheckReport and their types. full-check itself composes the other commands' own run*() functions, which the package root already exported.

DevToolz 0.2.0 ​

Package version history

  • New: unused-deps finds package.json dependencies nothing imports, and "phantom" dependencies that are imported but never declared. See Dependency Graph.
  • New: circular-imports finds import cycles and shows each as its full chain; cycles made only of import type are hidden unless --include-types is given. See Dependency Graph.
  • New: empty-catch finds catch blocks that swallow the error, including ones that only log it. See Code Hygiene.
  • New: todo-report collects TODO/FIXME/HACK comments with their text, with --tags and a --max ratchet. See Code Hygiene.
  • New: scripts-check cross-checks package.json scripts against README/docs and CI workflows, and orphan-tests finds test files whose source disappeared. See Consistency Checks.
  • New: stale-ts-ignore finds a @ts-ignore that no longer suppresses anything, by comparing two real project-wide typechecks. See Stale @ts-ignore.
  • Added to the programmatic API: the run*() and render*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's tsconfig.json loader was shared the same way.

DevToolz 0.1.0 ​

Package version history

  • First release: one devtoolz binary with six commands. See Overview.
  • strip-comments and console-strip remove comments and leftover console.log/debugger statements, with a preview by default, -y to write and --diff for a unified diff per file. See Code Cleanup.
  • dead-exports finds named exports nothing imports, aware of a package's public entry points, re-export chains and workspaces. See Dead Exports.
  • case-check finds imports whose case does not match the file on disk, with --fix. See Case Check.
  • exports-doctor and readme-check verify a package from a consumer's side: declared package.json paths against the disk, and README code blocks against the package's own types. See Package Checks.

Network Dashboard 0.4.2 ​

Package version history

  • Several addMock/addMockToGroup examples in the README and the Mocking guide omitted the required enabled field — 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/addMockToGroup check rule.enabled before applying it).
  • addMockToGroup's documented signature listed rule: Partial<MockRule> — the real type is Omit<MockRule, 'id'>, every field but id is still required.

Responsive Media 2.0.2 ​

Package version history

  • The Vue integration guide's useContainerState example called useTemplateRef('card') without an explicit type argument — Vue's own default (unknown) doesn't satisfy useContainerState's Ref<Element | null> parameter, so the example as written never actually compiled. Now shows useTemplateRef<HTMLDivElement>('card').

State Machine 0.2.7 ​

Package version history

  • The README's code examples still imported the unscoped vue-state-machine in 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 CheckoutCtx example declared it with interface — TypeScript doesn't give an interface the implicit index signature Ctx (Record<string, unknown>) needs, so WizardStep<CheckoutCtx> never actually type-checked as written. Switched to a type alias, matching the pattern already used elsewhere in the same doc.

September 24 ​

Color Value Tools 1.2.2 ​

Package version history

  • New subpath imports by function group: color-value-tools/parse, /convert, /manipulate, /palette, /a11y and /cache. They work with both import and require and 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.ts files.
  • The package is marked sideEffects: false, so bundlers can drop unused code more reliably.
  • The cvt CLI 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 ​

Package version history

  • sources entries can now carry their own width/height for art-direction breakpoints whose crop has a different aspect ratio than the root image — either as { src, width, height } or by passing a build-time ImageMeta object directly (e.g. from a ?vik import). 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 without width/height keep working exactly as before.
  • A sources key 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 ​

Package version history

  • <VImage> no longer forces display/box-sizing/object-fit as 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 explicit fit prop is still applied inline (guaranteed to win). Left unset, the object-fit: cover default now comes from a plain, overridable CSS class — applied only when the image box is actually constrained (layout"fill"/"fixed", or both width and height given), and omitted otherwise since it has no effect without a constrained box. The same applies to the base display/sizing styles — width: 100%; height: auto is now only applied when both width and height are given (there's no intrinsic ratio to preserve otherwise), so a bare <VImage> sized purely through your own max-height/max-width CSS 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's exports, so placeholderMode="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 ​

Package version history

  • Fixed: createRevealController's stagger delay (--reveal-delay / the inline transition-delay it 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 .reveal link, 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 CSS transition — 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 ​

Package version history

  • <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 new fadeIn prop (below) is a different, simpler effect, not a replacement for the old one.
  • <VImage>'s new fadeIn prop (default false) opts into a ~0.3s opacity fade-in on mount.

September 12 ​

Color Value Tools 1.2.1 ​

Package version history

  • isReadableOnBackground()'s wcagLevel now uses the same effective background color as minContrastRatio/readable for 'semi-transparent'/'gradient' backgrounds, instead of always '#ffffff'.

Command Palette 0.2.9 ​

Package version history

  • bindShortcuts now binds hotkeys for nested subCommands too, not just top-level commands.
  • The hotkey fallback executor (runFallback, used with no <CommandPalette> mounted) now correctly opens page-only commands and handles confirm/frecency tracking like the real executeCommand.
  • CommandItem's match highlighting now reuses the diacritic-aware FuzzySearch scorer instead of a separate, less accurate implementation.
  • The Nuxt module now registers the package's components via addComponent and auto-imports every composable/factory, not just 3 of them.
  • isLoading in CommandPalette.vue is 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 provides PALETTE_REGISTRY_KEY — named-instance lookups (useCommandPalette('name')) now resolve correctly under it.
  • Unified the global hotkey toggle (installPalette) and useCommandPalette()'s own toggle()/open()/close() onto one open/close implementation (including history clearing).
  • Function-valued Nuxt module options (vCommandPalette: onOpen, onError, search, onSearch, etc.) are no longer serialized into the client runtimeConfig.public — only the serializable subset crosses that boundary.

CSS Magic Gradient 1.3.1 ​

Package version history

  • Added reactive useMonochromaticGradient/useHueWheelGradient hooks to both css-magic-gradient/vue and css-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 ​

Package version history

  • <AsyncBoundary> is now auto-registered as a global component by the Nuxt module, alongside <ErrorBoundary>.
  • createHttpReporter now returns a cleanup function to remove its pagehide listener.
  • The Nuxt module's autoImports list now covers every composable/ factory in the package, not just 3 of them.

Feature Toggles 0.2.0 ​

Package version history

  • Added 'live' to the FlagSource type for SSE/WebSocket-pushed flag updates.
  • <Feature> with neither name nor group now logs a dev-mode warning instead of silently rendering nothing.
  • The Nuxt module now accepts loader/rules in its own config and auto-imports the package's composables.

Form Schema 0.2.8 ​

Package version history

  • @macrulez/nuxt-vue-form-schema is 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 own optionsDeps change.
  • isValid now accounts for a still-pending async validator, instead of only submit().
  • The default persistKey is no longer a plain comma-joined field-name list — two unrelated forms with identically-named fields no longer silently share persisted storage.
  • remove/move/swap on useFieldArray now correctly renumber form.errors/form.touched.
  • The Vue DevTools panel is now wired up automatically by the plugin's install() — no manual installFormDevtools(app) call needed.

i18n Kit 0.4.12 ​

Package version history

  • I18nKitConfig, LocaleConfig, and LocaleMeta are now exported from vue-i18n-kit/config, so they can type-check a hand-written i18n-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 ​

Package version history

  • v-lazy-img now shares the same pooled IntersectionObserver every other lazy-loading path uses, instead of creating its own per element.
  • Unset layout now gets the same auto-sizes heuristic as layout="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 ​

Package version history

  • Added the missing <InView> component and setViewportDefaults/ viewportDefaults registration to the Nuxt module (previously only composables/utilities/v-reveal were wired up).

Network Dashboard 0.4.1 ​

Package version history

  • Fixed the package's own npm run type-check — broadened the *.vue module shim to also declare <script setup>'s named type exports (e.g. NetworkDebuggerProps).
  • Cleaned up the dead/divergent useHotkey.ts/useLogFilter.ts composables that duplicated NetworkDebugger.vue's own inline logic.
  • Closed a dormant cross-test localStorage leak from a missing mock reset in the persistToStorage tests.
  • 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 ​

Package version history

  • 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, with resetDetectionCache() support.
  • Synced package-lock.json's version with package.json.

Responsive Media 2.0.1 ​

Package version history

  • isAbove(key) now correctly returns false for an unrecognized breakpoint key — fixed in the core, Vue, and React implementations.
  • Unified the two independent isSSR() implementations into one, stricter check (window and window.matchMedia both present).
  • Vue's useBreakpoints() now honors inject()/DI, matching useResponsive().
  • Vue's useMediaQuery() can no longer leak its matchMedia listener when called outside an active component — the composable now always returns a stop function.
  • React's useContainerState() now recreates its ResizeObserver if ref.current was null on 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 ​

Package version history

  • Reconciled config-based client caching between useRestClientVue (cached) and useRestClientReact (uncached) into one documented contract.
  • Clarified and documented WebSocket stage pass/fail semantics — no longer decided by close.wasClean alone, ignoring a visible onError.

State Machine 0.2.6 ​

Package version history

  • MachineStore.register() now warns in dev mode on an id collision instead of silently overwriting the prior entry.
  • useMachine() now auto-unregisters from the MachineStore/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 (including persist).

Storage Kit 0.2.7 ​

Package version history

  • useStorage() now warns in dev mode when a second caller for an already-live key+target passes different options (previously silently ignored).
  • Added a dev-mode warning when both throttle and debounce are set on the same call.
  • Added a dev-mode warning when httpOnly is set on the base (client-only) useCookie() outside the Nuxt SSR context.
  • compress() now surfaces a warning/error the same way encrypt()/ sign() already do, instead of silently degrading to pass-through.
  • React's useStorage now reacts to key/target changing across re-renders, matching the Vue version.

Toast Kit 1.1.1 ​

Package version history

  • ToastContainer's expand prop is now wired up (was declared but never read).
  • ToastItem.isGrouped now reflects real grouping state instead of always being false.
  • toast.update()/queue.update() now restarts the auto-dismiss timer when duration changes.
  • Synced CHANGELOG.md with the current package.json version.

Virtual Scroller Kit 0.3.1 ​

Package version history

  • Added containerRole/itemRole override props to VirtualGrid, matching VirtualList/VirtualTree/VirtualSelect.
  • Added test coverage for InfiniteLoader.vue (threshold logic, load direction, concurrent-load guard, scroll-position preservation on prepend loads).
  • Updated engines.node in package.json to match the toolchain's real minimum (Node 20/22).

Worker Kit 0.2.5 ​

Package version history

  • run()/map() on createWorkerPool/useWorkerPool no longer discard ctx.reportProgress()/ctx.reportChunk() — progress and chunks are now wired through WorkerPool.
  • useWorker() now exposes an explicit terminate() method.
  • A crashed worker (Worker.onerror) is now recreated on the next run() instead of reusing the broken instance.
  • With streaming: false, calling ctx.reportChunk() now logs a dev-mode warning instead of silently dropping the chunk.
  • Removed the stale "nuxt" keyword from package.json (no Nuxt module exists in this package).
  • WorkerComputedResult's fields are now wrapped in Vue's readonly(), enforcing the readonly typing at runtime too.
  • RetryStrategyOptions/StreamingOptions are now used as the real parameter types for UseWorkerOptions/UseSharedWorkerOptions instead of being redeclared inline.