Repository navigation
Releases: leefanv/liqui-design
Release list
@liqui-design/glass@0.5.0
Minor Changes
-
f9ee35e: Rework the surface optics toward the reference material look:
- Specular rim is now lit from the outline normal — a crisp ~1px stroke plus
a few px of diffuse glow on the top/bottom arcs, with a hairline shade on
the side flanks — instead of the positional-azimuth band, which lit
straight edges unevenly. It renders at full resolution, with a baked dark
variant that CSS swaps in under[data-theme='dark']/.dark. - The refraction filter gains a tone stage (
feComponentTransferlookup
table) that lifts the darkest backdrop tones and rolls off the brightest,
scaled down asfrostrises, so refracted content stays in a band the
foreground keeps contrast against. - Corners are continuous: the displacement map and lighting are generated on
a superellipse (|x|⁴+|y|⁴=r⁴) and the surface declares CSS
corner-shape: squircle(Chromium 139+), so optics and clip agree on one
geometry. Where the squircle actually renders, the declared radius is
inflated 1.4× internally — a superellipse reads "less round" than a circle
at the same number, and this keeps the perceived corner size of previous
releases. Browsers without the property keep round corners at the declared
value, unchanged.
- Specular rim is now lit from the outline normal — a crisp ~1px stroke plus
@liqui-design/glass@0.4.0
Minor Changes
-
a26446d: feat: two tokens for flat controls,
--lq-controland--lq-control-rimliqui's brand-coloured controls were glass that had been retinted: a checked
checkbox, a selected radio, a pressed toggle and anaccentbutton all worked by
overriding--lq-tintwith a mix of--lq-accent, so the accent arrived as a
lens and kept refracting the page through itself.That is the wrong side of the line Apple draws, and the reason is not taste.
Glass is for a surface you act through; a solid fill is for a control that
carries a value. An accent tint is the second thing wearing the first: the
whole point of the colour is that it says "this is the one", and the whole point
of the lens is that it lets the wallpaper through. In practice it meant the
accent was one blue over a bright photograph and a different one over a dark
backdrop — a brand colour that changed with the desktop.So those controls are now flat, and they need a resting surface that is not the
glass tint. The two tokens are it:--lq-controlis the fill of a flat control
at rest,--lq-control-rimits hairline edge, dark on a light theme and light on
a dark one. They join the themeable set, so they reachtokens.css, the registry
cssVarsblock and the theme editor like every other token.Nothing in the kernel changes:
LiquiGlassrenders exactly as before, and a
theme that does not mention the new tokens is unaffected.
@liqui-design/glass@0.3.0
Minor Changes
-
60a3550: Add
LiquiThemeProvider— global theming for the optics and the tokens.Colour was already themeable: every surface paints from a
--lq-*custom
property, so twelve variables in a stylesheet re-skin the library. The optics
were not.refraction,bezel,radiusandprofilefeed a canvas-generated
displacement map and an SVG filter, so they can only be props — and they are
per-component props, set to values scaled to each surface: a scroll-area thumb
asks forbezel: 4, a drawer for34. There was no way to say "make all the
glass thicker" without editing every component.The provider splits the dials the way they actually behave:
- Absolute defaults —
material,profile,frost,specular,
dispersion,saturation. The theme supplies the value a surface didn't;
an explicit prop still wins, so a component that asks forfrost: 0.6
because its design needs it keeps it. - Multipliers —
radiusScale,refractionScale,bezelScale,
blurScale. These apply to whatever each surface asked for, so the
proportion between a thumb and a drawer survives the edit.
theme.lightandtheme.darkaccept the twelve tokens as well, written into a
<style>at:rootfor themes that change at runtime. Portals are why it is
:rootand not a wrapper: a popup mounts ondocument.body, outside anything
the provider could wrap.An untouched theme is a no-op by construction — every multiplier is 1, every
absolute equals the existing default, and no<style>is emitted until a token
differs. Mounting the provider changes no pixel.Also: the scaled geometry is rounded before it reaches the displacement-map and
filter caches. Those are keyed on size and optics, so an unrounded multiplier
being dragged would mint a fresh canvas render and a<filter>node per frame.
Andbezelnow floors at 1px — a zero-width bezel divides through in the map
generator and turns the whole surface into NaN displacement.tokens.cssis now generated at build time fromsrc/tokens.ts, which is where
the token values live. The stylesheet is byte-identical for the same values;
what changes is that there is one copy of them instead of two. - Absolute defaults —
@liqui-design/glass@0.2.4
Patch Changes
-
d2af2cf: Give the forwarded ref a stable imperative handle.
useImperativeHandlewas called without a dependency array, so it re-ran on
every render — detaching the previous handle and attaching a new one each time.
When the forwarded ref is a callback ref, detaching means calling it with
null.Base UI hands exactly such a callback ref to any part belonging to a composite
list — a slider thumb, a tab, a menu item — and its cleanup unregisters the item
and schedules a state update. Render, detach, unregister, render: an infinite
loop, from a component that is only sitting on the page. Base UI 1.7 is where
that unregister path began scheduling the update, so that is where it surfaced,
but the unstable handle was the defect the whole time.The handle is a getter over a ref that outlives every render, so it depends on
nothing and is now created once.
@liqui-design/glass@0.2.3
Patch Changes
-
5c00b41: Evict filters by least-recently-used, not by age.
ensureFilterreturned early on a cache hit without re-inserting the key, so
the registry'sMapstayed in creation order and eviction removed the oldest
filter rather than the coldest one. Under the 128-entry cap that was mostly
invisible, because a page rarely held that many surfaces at once.It stops being invisible on a full page of glass. Every surface re-requests on
every frame of a window resize —ResizeObserverfires unthrottled — so a
dozen surfaces walk through hundreds of sizes in a couple of seconds and push
the filters that are actually on screen out of the registry. The<filter>node
gets removed, the surface'surl(#…)resolves to nothing, and Chromium drops
the wholebackdrop-filterchain. It never comes back: the reference is
memoised on size and optics, and neither of those changed, so nothing re-asks.
The surface just stops refracting, with nothing logged.The hit path now re-inserts, which is what the surrounding comment already
claimed it did, and the cap moves to 256.
@liqui-design/glass@0.2.2
Patch Changes
-
3bd20fa: Keep component retints working on the
clearmaterial.The clear tier used to reach legibility by overriding
--lq-tinton the surface
itself. That override won against anything a component set on the same element:
a checked Checkbox or Switch writes its accent from a Tailwind utility, utilities
are layered, and layered rules lose to this package's unlayered stylesheet. So
material="clear"silently turned every checked control back into a neutral
white track — an on/off switch that could not show "on", with nothing logged
anywhere.The tier now composites a neutral wash underneath whatever tint is in play
instead of replacing it. Densities are unchanged for surfaces that don't retint;
retinted ones now come through in their own colour. This matters most for
controls nested on another glass surface, whereclearis the recommended way to
give up a lens they can't use. -
3bd20fa: Let utility classes override a surface's base
position,border-radius,
isolationandcolor.Those four are defaults, but they were shipped as unlayered rules, and an
unlayered rule outranks any layered one no matter how specific — so Tailwind
utilities on a glass surface lost silently.fixedon a glass dialog stayed
relative, leaving the popup wherever the document flow put it instead of
centred on the viewport, andtext-whiteon an accent button never replaced
--lq-text. Neither logged anything; both looked like the component had been
styled that way on purpose.They now live in Tailwind's own
baselayer, which is declared before
utilities, so an override wins. With no Tailwind present the layer is created
by this file and any unlayered consumer CSS beats it — which is what a default
should do. The surface anatomy (the backdrop, tint, specular and content layers)
stays unlayered: nothing outside should be overriding that.
@liqui-design/glass@0.2.1
Patch Changes
-
c47ca4b: Add
authorandbugsto the package manifest, so npm links back to the
issue tracker now that the repository is public.This release also exercises the automated publish path for the first time.
0.2.0 was pushed by hand before trusted publishing could be configured — npm
requires a package to exist before you can name a trusted publisher for it — so
this is the first version whose provenance is attested.