Skip to content

v0.3.3

Latest

Choose a tag to compare

@benface benface released this 27 Sep 13:57
c55cdd8

monowind 0.3.3 is faster, blends opacity and translucent colors the way the browser does, and fixes a long list of layout and interaction bugs. The core package has less code than 0.3.2, and its CDN bundle is 7.5% smaller.

Faster

Measured against 0.3.2 in Chromium (medians, ms):

measure 0.3.2 0.3.3
prose page (300 paragraphs), until interactive 306 182
boxes page (300 boxes), until interactive 226 173
faded boxes page, until interactive 259 192
prose relayout (CPU) 88 65
prose hover (CPU) 97 74
popover fading over a page, CPU per frame 75–88 12–16
the same, frames in a 1 s fade 15–17 62–66
150 boxes fading at once, CPU per frame 143 52
  • A page load runs one layout instead of two.
  • Style recalculation takes about half the time: only elements with a transition get the settling pass, and two style rules that kept Chromium from sharing styles between elements are gone.
  • An opacity or border-color transition repaints each frame instead of laying the page out again, and a frame lays out at most once.
  • Shade glyphs (░▒▓) no longer defeat Chromium's style cache: pages full of them restyle a third faster.

Opacity and translucent colors

  • Translucent colors (bg-white/10, text-white/60) and opacity-* blend into the cells beneath them, as the browser composites them. A bg-white/10 card on a bg-slate-800 panel now tints the slate; in 0.3.2 it showed white over the host's background.
  • An opacity-* element fades as a whole, as in a browser: on a white page, a bg-blue-600 text-white opacity-50 button shows white text on a light blue fill.
  • A background of any alpha hides the glyph beneath it, and a color at zero alpha paints nothing.
  • Where nothing opaque lies beneath, translucent colors and faded elements keep their alpha, and the browser composites them over whatever is behind the host: an image, a gradient, the page.
  • Color emoji fade with their element, in Safari too.
  • Every CSS color space blends: lab(), lch(), oklab(), oklch(), and color()'s display-p3, a98-rgb, prophoto-rgb, rec2020 and xyz (0.3.2 misread display-p3 as sRGB).

Fixes

  • Shade glyphs (░▒▓, in scrollbar tracks, shadows and the blocks theme) draw once, at the density the font draws them. They were two to three times darker and banded row by row.
  • Sticky: a sticky element inside a fixed element, a popover or a dialog sticks to the right scroller; a sticky span inside a scrolling paragraph sticks; a sticky heading among text runs moves its native element with it.
  • Flex: reversed rows and columns and wrap-reverse match the browsers for every alignment keyword, positioned children included (start stays put where flex-start flips).
  • w-fit contributes its full width: a w-fit label in a flex row, a float, a positioned box or a table cell no longer wraps at its longest word.
  • Tables: a positioned child of a table sits where a row in its place would start, margins included.
  • Stacking in text mode: a z-* on an element no longer lifts its children's native elements, so clicks and selections land on the element the grid shows.
  • An element that stops being a box (a responsive block md:inline) drops its engine positioning.
  • An align-middle inline-flex text box lands on its row; a multicol's overflow columns can be scrolled to; gap rules on overflowing tracks meet the border correctly.
  • An outer inline element's background paints under its inner inline elements; a span inside a padded inline element no longer inherits that padding.
  • Text ending on an inline box that doesn't fit its line no longer gains an empty last line (or crashes beside a float).
  • The *-safe alignment classes (justify-center-safe, items-end-safe, …) align as their keyword; they used to align to the start.
  • Transitions: easing comes from the browser itself (linear(), steps(…, jump-start) and delays included); removing an element mid-transition no longer keeps the host laying out every frame; the host's theme colors follow a background transition to its end.
  • An inline viewport-unit min-/max- size wins over a class's calc() value, as the cascade has it.
  • A host inside display: none waits instead of laying out with zero-width cells; a removed host stops listening to window events and listens again when put back.

Vite plugin

0.3.2 pre-bundled a linked monowind (from a workspace or npm link), so the dev server kept serving the engine from before an edit. A linked engine is now served as is; an installed one is still pre-bundled.

Components

  • Item parts (Item, ItemText, ItemIndicator, ItemGroup, ItemGroupLabel) read the nearest listbox, select or combobox root in React, Vue and Svelte alike, so a SelectItem inside a ListboxRoot works.
  • The error for an item part outside a list root, or for an item's text or indicator outside its Item, names where the part belongs.
  • Vue: a bare boolean attribute sets its prop, as in HTML: <MenuTrigger as-child>, <MenuItem disabled>, <SelectRoot multiple> (in 0.3.2 they read as false). Every part's type carries its declared props and its element's attributes.
  • React: ItemText and ItemIndicator are typed as the spans they render, and every part's type carries its displayName.

Dependencies

  • @sveltejs/vite-plugin-svelte 7.3.1 (a dev dependency of @monowind/ui-svelte and the Svelte example).
  • The StyleX example moves to @stylexswc/unplugin 0.19.0.

Upgrading from 0.3.2

  • Shades look lighter. Scrollbar tracks, box-shadow rings and ░▒▓ borders show the font's own density, no longer the doubled one.
  • Reversed flex layouts may move where they used start/end (place-* utilities) or baseline: they now sit where the browsers put them.
  • Vue types: a part rejects a prop name that is neither declared nor an attribute of its element (0.3.2 accepted any name).
  • Wide-gamut screens: a blend clips each color to sRGB first, as browsers do on an sRGB screen, so on a wide-gamut display a translucent color outside sRGB comes out a little duller than the browser's own blend.
  • 〰 ㊗ 〽 🈂 take two cells, on the grid and in clusterWidth and textCells, as the East Asian Wide table has them.
  • A selection's first frame: a selection a script makes, or one a key extends into the host, can show the browser's own highlight for one frame before the grid's.
  • Fades: the main thread spends far less per frame, so fades run at two and a half to four times the frame rate. A fade over opaque cells costs the browser more paint per frame (about 17 ms against 2 when 150 boxes fade at once; under 2 ms for a popover).
  • Overflowing content aligns to the start, as in 0.3.2: a flex line, grid item or positioned box larger than its container sits at the start edge whatever its alignment, where browsers center or end it past that edge.