This update brings quality-of-life enhancements to TriFrost’s client-side utilities, focused on ergonomics and resilience in dynamic UIs.
Added
- feat:
$.goto
utility, a high-level navigation helper for declarative and ergonomic client-side routing with built-in handling for query merging, blank tab opening, and replace-mode navigation.
$.goto("/dashboard");
// → Navigates to: /dashboard
$.goto("/login", "replace");
// → Replaces current history entry with /login
$.goto("https://external.site", "blank");
// → Opens https://external.site in a new tab
// Current url: https://app.local/settings?page=2&theme=dark
$.goto("/account", "query");
// → Navigates to: /account?page=2&theme=dark
$.goto("/search?q=test", "query");
// → Navigates to: /search?q=test&page=2&theme=dark
$.goto("/search?q=test&page=3", "query");
// → Navigates to: /search?q=test&page=3&theme=dark
$.goto("/profile", {
replace: true,
includeQuery: true
});
// → Replaces history with: /profile?page=2&theme=dark
- feat: Default CSS media breakpoints now includes
tabletUp
, allowing you to target tablet and above. The current set of default breakpoints is now:
css.media.mobile /* <= 600px */
css.media.tablet /* <= 1199px */
css.media.tabletOnly /* > 600px AND < 1200px */
css.media.tabletUp /* > 600px */
css.media.desktop /* >= 1200px */
Where previously you'd do something like:
css({
[css.media.tablet]: {flexDirection: 'row'},
[css.media.desktop]: {flexDirection: 'row'},
[css.media.mobile]: {flexDirection: 'column'},
})
You can now shorten this to:
css({
[css.media.tabletUp]: {flexDirection: 'row'},
[css.media.mobile]: {flexDirection: 'column'},
})
Improved
- deps: Upgrade @cloudflare/workers-types to 4.20250722.0
- deps: Upgrade @types/node to 22.16.5
- deps: Upgrade bun-types to 1.2.19
- deps: Upgrade eslint-config-prettier to 10.1.8
- deps: Upgrade eslint-plugin-prettier to 5.5.3
- deps: Upgrade typescript-eslint to 8.38.0
- feat:
$.storeSet
now short-circuits when provided value equals the current value, reducing unnecessary storage operations. - feat:
$bind
avoids re-binding already-bound inputs if passed multiple times, preventing redundant event wiring. - feat:
$.uid
now falls back toDate.now()
+ RNG ifcrypto.randomUUID
is unavailable - feat: Automatic Cleanup for
$.on
event listeners. Listeners are now auto-unregistered when a VM unmounts, an element is detached from the DOM, dynamic elements created via$.create
are removed.
$.on Before (Manual Cleanup)
const listener = $.on(window, "resize", () => {
console.log("Resized");
});
el.$unmount = () => {
listener();
};
$.on After (Automatic Cleanup)
$.on(window, "resize", () => {
console.log("Resized");
});
// No manual cleanup needed — handled by the VM and node itself
The same applies to:
- Element listeners (
$.on(el, "click", ...)
) - Global listeners (
$.on(window, "keydown", ...)
) - Listeners added to dynamically created elements using
$.create("div")
These changes reduce boilerplate and improve durability, especially in ephemeral or reactive UI flows.
As always. Stay frosty. ❄️