Skip to content

Releases: leefanv/liqui-design

@liqui-design/glass@0.5.0

Choose a tag to compare

@github-actions github-actions released this 14 Oct 10:37
fae9f2d

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 (feComponentTransfer lookup
      table) that lifts the darkest backdrop tones and rolls off the brightest,
      scaled down as frost rises, 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.

@liqui-design/glass@0.4.0

Choose a tag to compare

@github-actions github-actions released this 21 Sep 13:41
50f3871

Minor Changes

  • a26446d: feat: two tokens for flat controls, --lq-control and --lq-control-rim

    liqui's brand-coloured controls were glass that had been retinted: a checked
    checkbox, a selected radio, a pressed toggle and an accent button all worked by
    overriding --lq-tint with 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-control is the fill of a flat control
    at rest, --lq-control-rim its hairline edge, dark on a light theme and light on
    a dark one. They join the themeable set, so they reach tokens.css, the registry
    cssVars block and the theme editor like every other token.

    Nothing in the kernel changes: LiquiGlass renders exactly as before, and a
    theme that does not mention the new tokens is unaffected.

@liqui-design/glass@0.3.0

Choose a tag to compare

@github-actions github-actions released this 30 Aug 11:49
1cf0970

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, radius and profile feed 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 for bezel: 4, a drawer for 34. 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 for frost: 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.light and theme.dark accept the twelve tokens as well, written into a
    <style> at :root for themes that change at runtime. Portals are why it is
    :root and not a wrapper: a popup mounts on document.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.
    And bezel now floors at 1px — a zero-width bezel divides through in the map
    generator and turns the whole surface into NaN displacement.

    tokens.css is now generated at build time from src/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.

@liqui-design/glass@0.2.4

Choose a tag to compare

@github-actions github-actions released this 30 Aug 07:22
e671067

Patch Changes

  • d2af2cf: Give the forwarded ref a stable imperative handle.

    useImperativeHandle was 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

Choose a tag to compare

@github-actions github-actions released this 21 Aug 04:08
db2f98a

Patch Changes

  • 5c00b41: Evict filters by least-recently-used, not by age.

    ensureFilter returned early on a cache hit without re-inserting the key, so
    the registry's Map stayed 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 — ResizeObserver fires 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's url(#…) resolves to nothing, and Chromium drops
    the whole backdrop-filter chain. 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

Choose a tag to compare

@github-actions github-actions released this 14 Aug 03:51
7a2c48a

Patch Changes

  • 3bd20fa: Keep component retints working on the clear material.

    The clear tier used to reach legibility by overriding --lq-tint on 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, where clear is the recommended way to
    give up a lens they can't use.

  • 3bd20fa: Let utility classes override a surface's base position, border-radius,
    isolation and color.

    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. fixed on a glass dialog stayed
    relative, leaving the popup wherever the document flow put it instead of
    centred on the viewport, and text-white on 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 base layer, 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

Choose a tag to compare

@github-actions github-actions released this 06 Aug 06:33
f4bb37d

Patch Changes

  • c47ca4b: Add author and bugs to 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.