Skip to content

1.7.0: one site, new studio shell and home, tiles; React 18 and accent fixes

Latest

Choose a tag to compare

@xhunn xhunn released this 05 Nov 02:42
c28f1f9

The one-site release. Every chapter and gallery example is a native, pre-rendered studio page in one tile language, with its own head; old links land in the studio. The studio has a new shell (search, one-button mode, custom color, icon rail, sticky side nav, On this page) and a new home (live product hero, ambient Get started). Package changes: .badge.bloom is neutral; the React parts run on React 18 and 19 (react/inert.ts); LiveActivity gains optional emptyAction and onOpenChange; verseva add warns below React 18; the console and landing blocks hold at phone width. No class or token is renamed.

Added

  • design.verseva.com is pre-rendered. Every route in the studio routes table ships its own HTML: real headings
    without JS, a unique title and description, a canonical on design.verseva.com, Open Graph and Twitter tags, and
    JSON-LD (BreadcrumbList, plus WebSite on home). Pages hydrate in place, and client navigation keeps the whole head
    in step. The SPA rewrites in vercel.json are gone: each route is a file.
  • SEO kit, generated at build time from the emblem and the dark canvas tokens at full clear space: favicon.ico,
    icon.svg, apple-touch-icon.png, 192 and 512 icons plus a maskable one, the og.png social card,
    site.webmanifest, robots.txt and sitemap.xml (every route).
  • A studio 404 page. Unknown paths return 404 with the studio shell and a way back to Overview (noindex).
  • The gallery lives in the studio. /gallery is a native page, and each example opens at /gallery/<slug>
    (the example in a frame that fits its document and follows the studio theme and brand) with its source at
    /gallery/<slug>/code (pre-rendered, with Copy). Links inside an example route through
    the studio. /examples/*.html still serve as files.
  • Components links to Widgets from its header.
  • Old site links land in the studio. /code.html?f=examples/<slug>.html (and /site/code.html?f=) 308s to
    /gallery/<slug>/code; any other code.html request goes to /gallery. Every /site/<page>.html 308s to its
    studio route (/site/index.html to /, /site/examples.html to /gallery), as the root copies already did. The
    registry JSON (/r/*, /site/r/*), /examples/**, /site/examples/**, site.css and theme.js stay files.
  • Studio command bar. The top bar search (⌘K / Ctrl K) opens the package command bar over every route and
    every chapter and page section, built from the routes table and the section ids. A result navigates in the shell
    and lands focus on its section. Below 900px the search is an icon button and the bar is a full-height sheet.
  • Custom accent. The color dot opens a popover with the five presets and Custom: a hue control and a hex field.
    Any pick is derived to --accent, --accent-hover, --accent-ink and --focus for dark and light, gated live
    (ink on accent and hover at 4.5:1, the accent and its hover on bg at 3:1, the accent on both surfaces at 3:1, text on the
    accent tint at 4.5:1; hover steps away from the page, as the presets do), and
    moved in OKLCH lightness to the nearest passing value when it fails, with the adjusted value and a pass or fail per
    check shown. The hue control changes only the hue of the original pick, so stepping back returns it. The popover
    traps focus while open. A chunk that fails to load shows a Retry in place. The choice persists and applies before first paint. Copy theme copies a ready
    [data-brand="custom"] theme file in the presets' shape (contrast-gate clean).
  • Icon rail. The sidebar collapses to a 72px rail: one icon per Studio page and one per group, a tooltip on each,
    and a keyboard-operable flyout per group (arrows, Home, End, Enter, Esc back to the icon). The rail state persists
    and applies before first paint.
  • On this page. Chapter and Foundations pages carry a right rail of their sections from 1200px, with scroll-spy
    (aria-current="location") and focus moved on click.

Changed

  • Top bar. The studio header is the package three-column .tbar: lockup and version, the search trigger,
    then color, mode, pause motion and GitHub. Mode is one icon button that cycles light, dark and system, named
    "Theme: current. Switch to next", announced politely, and drawn from the head script's data-mode so it never
    shows a wrong icon. The five brand chips and the Light / Dark / System segmented control left the top bar (the
    Overview hero keeps its theme picker). The npm link left the bar.
  • Sidebar. Studio, Chapters and Gallery are collapsible groups (open state persists; the group holding the
    active item stays open), Gallery lists its examples, counts stay neutral badges, and the active item carries the
    nav bloom. Per-chapter section anchors left the sidebar for the On this page rail and the command bar.
  • Phone shell from 900px. The page and section select and the stacked header now apply below 900px (was 760px).
  • Lazy chunks. The command bar (studio and /widgets), the color panel and the search commands load on first
    intent; their triggers stay in the main chunk, which measures 147.1 kB gzip under the unchanged 150 kB budget.
  • Studio home (/) is a live product hero. "One source. Every surface" with one primary action, Get started
    (copies npm i @verseva/design, shows Copied, then lands on /components#install), and a quieter Browse
    (/components). Beside it, a real widget home on the package parts (.wgrid tiles): the smart stack rotates with
    its visible pause, a demo job ticks in the live activity capsule, and the focus widget's chart settles. Only the
    focus widget carries the accent. At phone widths the home drops to two tiles and the CTA stays above the fold.
  • Ambient motion on the home. Get started carries a slow catch-light sweep inside its matte body (transform only,
    no glow, no outer shadow), held on hover and focus. A neutral drift (text-ladder and surface tones, no accent)
    moves behind the hero. Both start after mount and stop under Pause motion and under reduced motion.
  • Entry tiles into Components, Widgets, Foundations and Gallery, labels and counts only, in the /widgets tile
    language, routed in the shell. The theme picker, token readout, frame stage and counts row leave the home (the
    header's color popover and Foundations carry them); the home no longer loads the 3D stage.
  • Studio specimen tiles. Components and Foundations take the /widgets tile language: the package .wgrid
    bento and .wtile glass at --r-lg, with a header (category icon, name, neutral meta count), the live specimen
    in the body, and Show code with Copy in the footer. Tiles size to their content (S, M, L, XL; rows hug the
    specimen), XL drops to the M span under 1100px and every tile to one column under 560px. The tile carries the
    loading, empty and error states, and is one component (studio/src/tiles/SpecimenTile.tsx) for the chapters
    and the gallery to follow.
  • Components: 50 sections as tiles. Section ids, deep links, the On this page rail and the demos are
    unchanged; each code panel shows the generated, byte-checked sample from chapter-code.mjs.
  • Foundations: each token family is a tile, with its declarations (:root and the light flip) as its code.
  • Gallery: a bento of example tiles. /gallery shows the 8 mock sites as XL, M and S tiles: the name and its
    tags as neutral badges in the header, a live thumbnail in the body, Live (/gallery/<slug>) and Code
    (/gallery/<slug>/code) in the footer. The tag filter chips stay, as neutral selection, with a count on each.
    Thumbnails are the example files scaled from 1280px: inert, aria-hidden, no pointer events, themed and branded
    with the studio. They load lazily (IntersectionObserver), at most 6 at once, 3 on phones, and sit still (CSS
    animations at their end state, the example's animation-frame loop held) until their tile is hovered or holds
    focus; never under Pause motion or reduced motion. Details and inspiration shots are tiles too.
  • Gallery example and code routes in the tile language. /gallery/<slug> puts its frame in a tile (the file
    and tags in the header, Code in the footer) and /gallery/<slug>/code its source (Open live and Copy in the
    footer, Retry in the body on a failed chunk). Height fitting, theme and brand following, one scrollbar, the
    pre-rendered source, the breadcrumb JSON-LD and the 404s for unknown slugs are unchanged.
  • Retired: gallery parity. /gallery and the code route no longer match site/examples.html and
    site/code.html element for element; both are logged in studio/test/redesigned.ts and held by
    gallery-tiles.test.tsx and the served gallery.test.mjs instead.
  • Web UI, Distribute and Docs + PDF as tiles. Web UI: the ladders, type trio and radius tables, then the four
    contract specimens (Buttons, Status, Card + stat, Segmented + field) under their section. Distribute: the command
    blocks, the agent tool table and the theme presets. Docs + PDF: the memo in one XL tile. Section ids, cold deep links
    and the On this page rail are unchanged; the bento has no holes at 4 and 2 columns. The legacy doctrine sublabels
    above the Web UI specimens are gone (labels and counts only). These pages have no generated code samples, so their
    tiles show no code.
  • Data viz, Motion and Decks as tiles. Data viz keeps law 3 the way a product must: one focus tile (Line + area)
    spends the data accent and the other nine charts draw on the text ladder. Motion's Replay, Roll it, Point at it,
    Resolve it and Open it sit in their tiles' footers; the theme wipe, the curves race and the Pause motion control
    work as before. Decks: the slide and the structure table side by side. The Data viz and Motion samples load on
    first intent (main chunk 141.22 to 137.56 kB gzip).
  • Data viz recipes follow the data-intensity rule. Bar magnitude goes through data-l (new .bar .fill[data-l]
    rungs in components.css, with their text-ladder twins in a tile without data-focus), Stacked segments take
    series identity (series one, --data-alt, a neutral third on --text-2) instead of the magnitude ladder, the intensity legend
    uses the same rungs as its cells, and the source dot uses a neutral token, not --success. No chart colour is
    inline. The Data viz samples are generated from these specimens as drawn and held byte for byte
    (specimen-code.test.tsx), so a sample cannot drift from what renders.
  • Chart marks clear 3:1 and their labels 4.5:1 in both modes. The text-ladder rung 1 a tile without data-focus
    draws (bars, heat cells, activity strips) lifts from 30% to 50% --text-1 (light was 2.0:1, dark 2.6:1); the
    Stacked third series fills --text-2 with a --bg label, and the Priced label takes --surface (4.46 to 5:1).
  • SpecimenTile focus prop (default true): false drops data-focus, so the package recolours the tile's charts.

Fixed

  • Gallery sources load per page, not in the main bundle. Each /gallery/<slug>/code route loads only its own
    example's source as a separate chunk; the pre-rendered page still holds the full text without JS and hydrates with
    it in place. The main entry chunk drops from 176.3 kB to 146.8 kB gzip, held under a 150 kB budget by
    test/served/bundle.test.mjs, which also fails if any example source returns to it.

  • The landing example holds at phone width. Below 600px its nav wraps the section links to their own row, so
    examples/landing.html is 375px wide at 375px (was 433px). Unchanged at 1280px.

  • Components no longer scrolls sideways on phones. The #table specimen sits in its .tscroll scroller and the
    #table-pin specimen lets its .pin.box scroll, at 375px.

  • Theme before first paint. The inline head script runs ahead of every stylesheet, and the Mode control shows the
    stored mode from first paint instead of sliding from System after load.

  • /<route>/index.html opens that route instead of the not-found page.

  • Overview's Pulse and Launch tiles open their gallery pages (/gallery/pulse, /gallery/launch) inside the
    studio, instead of the bare example files.

  • What's new New tag spends no accent. .badge.bloom moves from --accent-bloom to the text ladder:
    --text-1 at weight 600 on --surface-2, a step above Improved (--text-2). Law 3 budget: counts and info
    badges are neutral. The console-view accent test now renders an open What's new drawer.

  • Studio Pause motion stops every auto-moving element (WCAG 2.2.2). The header control now stops every CSS
    animation on the page and in same-origin example frames (marquee, border beam, spinners, shimmer) and the
    Live now smart stack's rotation, as well as the 3D stage. Reduced motion is unchanged.

  • In-page anchors move focus (WCAG 2.4.1). Ported chapter anchors, including the skip-link specimens
    (#sh-main, #shr-main), scroll and focus their target, adding tabindex="-1" where it is not focusable.

  • Deep links clear the sticky studio header. Every studio scroll margin reads one variable,
    --studio-scroll-pad, built from the header's and the phone page select's measured heights (191px and 61px at
    375px, 66px at 1280px), with per-breakpoint fallbacks. Cold deep links now land on their section.

  • React 18 consumers: widget-grid and smart-stack compile and work again. Both set inert, which
    @types/react 18 does not know, so tsc failed on React 18 projects; React 18 also drops a boolean
    inert, so edit mode and hidden stack pages were not inert there. A new registry util, inert
    (react/inert.ts), renders inert on both: true on React 19, "" on React 18. Re-add the two parts
    (npx verseva add widget-grid smart-stack, which brings inert). Every registry React part now
    type-checks against @types/react 18 and 19 in CI. React 18 or later is needed for the React parts
    only; the CSS, tokens and preset need no React, and the package declares no React peer, so it installs
    into any project. verseva add warns in one line when it copies React parts into a project on an
    older React.

  • Skip to content (WCAG 2.4.1). Every studio route opens with a "Skip to content" link, the first
    focusable element of the shell, hidden until focused, with the focus ring. It moves focus to the page's
    main content, in the pre-rendered HTML and after hydration.

  • The /widgets console keeps its phone nav. The Home console specimen carries a .navshell below
    900px, where the console hides its sidebar, inside the specimen instead of fixed to the page.

  • Overview's Pulse and Launch covers open without a page reload. They route through the studio like
    every other studio link.

  • Components and the console example hold at 360px. The #bulk table specimen sits in a .tscroll
    scroller (it spilled past its box and scrolled the page sideways below 372px), and
    examples/console.html (and blocks/console.html) tightens its quotes table cells below 400px
    (366px wide at 360px before).

  • Old /code.html?f= links land on a clean URL. The redirect passed its query through, so the code
    page opened at /gallery/<slug>/code?f=...; the studio now drops the stray f in place, on any
    gallery route.

  • On this page marks the deep-linked section on a page too short to scroll (Decks at 1440x900: both tiles in
    one row below the line marked Slide anatomy for /decks#structure).

  • Gallery: the filter shows its result. A filtered-out tile is no longer rendered (its display:none lost to the
    package .wtile display in the built CSS, so all 8 stayed on screen). Each filter's subset is sized to fill every
    row at 4 and 2 columns (its own sizes when they fit, else an XL first on an odd count and Ms in pairs), and the
    result is announced politely ("2 examples").

  • Gallery: a thumbnail that does not load shows the tile error with Retry. A missing example answers with the
    studio shell (404.html); the tile no longer nests a studio in its thumbnail.

  • Gallery: the details bento has no holes (Count-up stat and Skeleton to loaded take M), and the gallery joins the
    chapter copy guard (no em dash, no doctrine sublabels, every legacy text accounted for).

  • 3D hero example: the copy holds its contrast over the scene. The scene read its colours once at load, so a
    frame the studio flips to light after load kept a dark knot behind dark copy (about 1:1). It now re-reads the tokens
    on every theme or brand change and when a theme sheet lands, with light-mode lighting from the surface tones. A
    directional scrim in the ground colour sits between the scene and the copy (left to right on desktop, a band on
    phones), and the hint sits on a pill. A served probe samples the scene behind every line of copy over several
    frames, in both themes at 1440 and 375: headline and body at least 4.5:1, kicker and hint at least 3:1.

  • The studio side nav stays fixed while the page scrolls. Expanded and collapsed to the rail, it sits below the
    header at full height, scrolls its own list when that is longer than the viewport, and keeps the collapse toggle
    in view at its foot (the expanded toggle had scrolled out of reach on long pages).

  • Home: the demo job is quiet. It ticks visually but says nothing in its live region until the visitor opens the
    capsule panel.

  • Home: Copied is honest. Get started says Copied only once writeText resolves. When the clipboard is denied or
    missing, or writeText throws, it says "Command below" and still lands on /components#install with focus there.

  • Home: the demo restarts. Restart sits in the capsule panel whenever no job runs (done, rested or cancelled),
    and Cancel now stops the job. With the panel shut after a Cancel, a Restart shows in the tile instead.

  • LiveActivity takes emptyAction and onOpenChange. emptyAction renders in the panel's empty state (a
    Restart, a Start); onOpenChange reports the panel opening and closing.

  • Dropped the unused .picker-lg rules from studio.css.

Tests

  • test/served/sidebar.test.mjs: at 1280, /components scrolled to its end, the sidebar's top stays at the header
    bottom, it fills to the viewport bottom, and its collapse toggle is in view, expanded and collapsed.
  • test/served/home.test.mjs: the law 3 accent budget on / at 1440 and 375 in both schemes (with a planted
    spend), the hero's animations (running, transform and opacity only, stopped by Pause motion and by reduced
    motion), Get started in Chrome (copied and denied, focus on #install), the budget with the job panel open, and the 375px fold at 667, 812 and 360 by 640. The served harness takes
    reducedMotion.
  • The Components port's element-for-element parity with site/components.html (markup, <style> and the
    FROZEN pin) is retired, as the redesign changes its presentation on purpose (studio/test/redesigned.ts). The
    tile contract test (specimen-tile.test.tsx) replaces it; the specimen-to-sample and chapter script tests stay.
    Other chapters keep their parity tests.
  • The class-name rule now covers the studio tile CSS.