Skip to content

Releases

0.2.0

Choose a tag to compare

@srivera145 srivera145 released this 21 Oct 17:56

This was going to be 0.1.4. One default below changes how existing pages look, and in 0.x a breaking change moves the minor version, so it is 0.2.0. A ^0.1 range or a CDN URL pinned to @0.1 stays on 0.1.3 until you move it to ^0.2 or @0.2.

Breaking

  • Primary buttons are lighter in dark mode. .btn-primary now fills with --brand and --brand-hover (see An exact brand colour reaches .btn-primary under Fixed). In dark mode those are the 400 and 300 steps, so the button takes the lighter colour a link uses, with black text. Until now it was the 600 step with white text in both schemes. Light mode is unchanged. To keep the old dark look, add one line to your CSS: @layer app.overrides { .btn-primary { --brand: var(--brand-600); --brand-hover: var(--brand-700); --btn-text: var(--text-on-brand); } }. It matches 0.1.3 at rest and on hover, in both schemes.
  • The npm package no longer carries the docs build data. dist/api.json, dist/api-buckets.json, dist/usage.json and dist/collisions.json describe Deck to its documentation site and editor extension, and nothing in a page or in npx @echodial/deck reads them. The tarball is 2.3 MB unpacked instead of 4.3 MB. If a script of yours read them from node_modules, take them from the Composer package or the repository, which still have them.
  • Two fixes below also change existing markup, and each says what to do if you relied on the old behaviour: .scroller's new padding (Focus rings inside lists and scrollers are whole and Scrolled cards rest at the gutter), and the on state a .btn now has with aria-pressed="true" (Toggle buttons, under Added).

Fixed

  • Modals open centred. .modal now sets margin: auto. The reset's * { margin: 0 } removed the browser's own centring of modal dialogs, so every .modal opened with showModal() sat in the top-left corner of the window.
  • Icons in running text stay on the line. .icon is now display: inline-block. The reset's svg { display: block } put an icon inside a sentence on a line of its own, despite .icon's baseline alignment. Icons in flex and grid rows (buttons, alerts, tiles, fields) are laid out exactly as before, because flex and grid items are blocks either way.
  • Long modals keep their footer. An open .modal is now a flex column, and so is a <form method="dialog"> wrapped around its regions. .modal caps its height at min(85dvh, 48rem) and clips, and .modal-body was meant to scroll, but an open modal was laid out as a block, so the body never shrank: in a window shorter than the dialog, everything past the cap was clipped, the footer and its buttons included. Now the body scrolls while the header and footer keep their height. flex-direction: column is on .modal itself rather than on .modal[open], so the regions stay stacked while a closing modal fades out.
  • Dark mode no longer has light blocks in it. .progress, .ring, .spinner, .skeleton, .range and .range-pair drew their tracks with --ink-100 and --ink-200, and the status badges, alerts and .banner-warn filled with --good-100, --warn-100 and --bad-100. All of these are fixed light values, so each drew a near-white shape on a dark page, and a .btn-ghost inside .alert-good, .alert-warn or .alert-bad was all but invisible (1.03:1). They now use theme-aware tokens. Light mode is unchanged, pixel for pixel.
  • The combobox placeholder is escaped. data-placeholder was written into the combobox's markup unescaped, so a placeholder containing a double quote could add attributes to the input, an onfocus handler included, and an ordinary placeholder with a quote in it was cut short. It is now escaped like every other string the combobox renders. The markup and data attributes are unchanged.
  • .banner-close clears the 44px touch target. It was only as big as its icon, 25×22px. It is now a --tap square with the icon at its old size, and it reaches into the banner's padding rather than making the strip taller. A .btn.banner-close is unchanged, because .btn already had a 44px target.
  • The combobox list opens next to its field. Where the browser has anchor positioning, the list covered the field it belonged to on every page, because position-area was measured inside .combo, which is only as tall as the control. On a phone inside a .card, the list was laid out against the card rather than the screen, since the card's contain: layout captures even position: fixed, and the card's overflow: clip then cut it off. deck.js now opens the list as a popover in the top layer, so no ancestor can clip it, and places it with anchor positioning, the Floating UI adapter, or its own placement, in that order. On a phone it stays anchored to the field, with 44px rows, instead of becoming a sheet across the bottom of the screen.
  • Remote comboboxes keep earlier choices, and post them. With data-url and data-multi, a choice made under one query was dropped by the next unless the new results happened to contain it, and no remote choice ever reached the <select>, so the form posted none of them. The selection is now kept apart from the results, every chosen value is written into the <select>, a token can be removed whatever the current results are, and a slow reply to an old query no longer replaces a newer one's results.
  • Long comboboxes open at once. Only the options near the scroll position are drawn, so 10,000 options open in about 16ms instead of 1.4s (Edge). The arrow keys still reach every option and wrap at the ends, PageUp and PageDown move a screenful, and the active option is announced through aria-activedescendant with its place in the whole list. The docs had always said aria-activedescendant was set; it was not. ArrowUp with nothing active now goes to the last option rather than the second-to-last.
  • Focus rings inside lists and scrollers are whole. .list clips, so a focused .list-row lost the sides of its ring, plus the top on the first row and the bottom on the last. The ring is now drawn inside the row, and follows the list's rounded corners. .scroller clipped the top of every focused item's ring and faded the ring of an item at the end edge. It now has 4px of top padding, so content below a scroller moves down 4px. Its fade lifts while keyboard focus is inside.
  • Scrolled cards rest at the gutter. .scroller has scroll-padding-inline equal to its own inline padding. Before, the first card snapped flush against the screen edge on load, and so did any card scrolled into view. A scroller you have made flush with padding-inline: 0 needs scroll-padding-inline: 0 as well.
  • .card-link responds to keyboard focus. Tabbing to the stretched link, or to anything else in the card, gives the card the same lift as hover.
  • .nav-link keeps one height with or without an icon. It is now inline-flex with centred items, so an icon no longer sits on the text baseline, where its size and the font could make the link taller. Text-only links are the same size as before.
  • A .btn label split at a bare <span> reads as one phrase. Save <span>changes</span> used to put the 8px gap between the words. A span with no class and no child elements now joins the label's text. A span with a class, such as a badge or .sr-only, keeps its box and the gap.
  • .form-actions-sticky sits above .tabbar. It used to slide underneath the tab bar. body:has(.tabbar) now publishes its clearance as --tabbar-clearance, the sticky bar uses it, and the bar drops its own safe-area padding while the tab bar is showing.
  • aria-pressed and aria-selected both mean "on". .chip, .reaction and .datepicker-preset used to respond only to aria-pressed="true", and .segmented only to aria-selected="true", so the wrong one showed no state and raised no error. All four now accept both, with the same look as before. deck.js moves either attribute when a .segmented is clicked, and no longer selects an aria-selected table row that contains one.
  • Small pointing icons mirror under dir="rtl". The automatic mirror in src/19-logical.css matched #chevron-right but not #chevron-right-sm, so an .icon-sm arrow or chevron kept pointing the wrong way in a right-to-left page. Every pointing icon is now listed with its -sm cut.
  • .g-scrim darkens an <img> child. The scrim painted under every child, so with the photo as an <img>, rather than as the element's background, the caption sat on the bare image. An img, picture, video, canvas, svg, iframe, .lazy or .video child now sits under the scrim; other children still sit above it.
  • A failed .lazy image shows that it failed. deck-extras.js set .is-error on the frame and nothing styled it, so the shimmer ran forever. The shimmer now stops and a broken-image glyph appears in the frame. The script also catches an image whose markup src failed before the script loaded, which fired no event.
  • .grid-fixed-2, -3 and -4 work without .grid. They set only the columns, so on their own they did nothing. Each now sets display: grid and the gap itself; grid grid-fixed-3 is unchanged, and print unwinds them like .grid.
  • .split-rail-start is described correctly. It sizes the first track as the rail, so the rail goes first in the markup. Its comment and the split docs said the opposite, and the docs example showed the main column squeezed into the rail's width.
  • .file takes a dropped file. It looked like a drop zone and ignored drops. With deck-extras.js, dragging a file over it sets .is-over (a solid border and the focus ring), and a dropped file goes into the input as a pick would: filtered by accept, one file unless multiple, then input and change. A drop the page's own handler has already taken is left alone.
  • SortableJS can load after Deck. With Deck deferred, a So...
Read more