Releases: lablup/ui-common
Release list
v0.2.0-alpha.15
First published 0.2 prerelease: @lablup/ui-common rebuilt on Astryx 0.6.2, plus the new @lablup/ui-common-cli. Published under the next dist-tag; latest/alpha stay on the 0.1 line.
Breaking for 0.1 consumers. Read CHANGELOG.md — Upgrading from 0.1 and docs/migrating-to-0.2.md, then:
pnpm dlx @lablup/ui-common-cli@next upgrade --from 0.1 --dry-run
pnpm dlx @lablup/ui-common-cli@next upgrade --from 0.1Highlights:
- Generated 1:1 mirror of
@astryxdesign/coreunder@lablup/ui-common/*; Lablup brand theme (theme/lablup);Modal/AlertModalreplace Astryx dialogs; 30+ components moved in from backend.ai-ui;Formengine andDataGrid. - React 19.2 or later and
@stylexjs/stylex^0.19 are required peers. pnpm 10+ consumers needallowBuildsfor@astryxdesign/core/@astryxdesign/cli(see README). - Every shipped stylesheet declares the cascade layer order, so ui-common's rules rank above Astryx's in any bundle.
- The CLI is its own package (
@lablup/ui-common-cli, binui-common), so the library's production install no longer carries the codemod toolchain (196 MB → 31 MB for a library-only app).
Full notes: CHANGELOG.md (0.2.0-alpha.0 – alpha.15). PRs: #53, #54.
v0.1.0-alpha.23
Added
DigitPopIn: renders formatted text one character at a time, each rising into place from a light blur, and replays when the text changes. Screen readers get the plain text; reduced motion gets plain text with no animation.StatCardtakesanimate="digits".animatealso accepts"count";trueis still the count-up.
v0.1.0-alpha.22
Fixed
- DataTable now preserves declared, restored, and resized column widths in the rendered browser layout.
- Tables whose columns fit still fill their container, while wider tables keep horizontal overflow inside the existing local scroll region.
v0.1.0-alpha.21
Added
- DataTable resize handles now support pointer and keyboard input, expose measured widths and finite ARIA ranges, and accept localized accessible labels and value text.
- Columns can define an optional maximum resize width while fixed columns keep their prior unbounded behavior unless they opt into a maximum.
Fixed
- Resize pointer cleanup is pointer-specific and safe across cancellation, lost capture, and reentrant release.
- Resize grips reserve a 32px target and meet the 3:1 non-text contrast floor in the shipped light and dark themes.
v0.1.0-alpha.20
New Features
None.
Improvements
None.
Bug Fixes
- Applied declared DataTable minimum widths to initial, restored, and resized columns and both header and body cells (#43).
- Aligned table headers and values consistently by default while preserving explicit physical left, right, and center alignment (#43).
- Moved Drawer focus after visible opening, preserved focus when close callbacks change, and assigned distinct accessible IDs to coexisting drawers (#43).
CI/CD Improvements
None.
Technical Details
Added regression coverage for table sizing and Drawer focus, dismissal, and accessible identity. Existing component APIs and React peer ranges were preserved.
Dependencies
None.
Breaking Changes
None.
Known Issues
None identified in this release's changed behavior.
v0.1.0-alpha.19
One new component and one accessibility fix.
Added
Select (#37, proposed in #16). A single-select listbox with an optional search filter, icons, descriptions, a disabled-but-visible option state, a field label, and the invalid and aria-describedby props a form needs. The listbox is portalled, so a select near the bottom of a scrolling panel is not clipped by it.
It is here because rule 2 passed, which is the test that usually fails: backend.ai-go and continuum-hub both ship this component with the same option shape and the same core props. The superset came, not the intersection, so a consumer does not have to wrap the package to get the label and the filter back.
Two things changed on the way in. The empty-search line resolved a product locale key and is now noOptionsLabel with an English default. The focus border was painted from the bare accent, which measures 2.61:1 against white in one shipped family, under the 3:1 WCAG 2.2 SC 1.4.11 asks of a focus indicator; it mixes the accent with the text colour now.
Fifteen tests, where both products had none.
Skeleton takes decorative, and styles/base.css gains --token-colorTextDisabled, --token-colorTextPlaceholder and --token-colorPrimaryBgHover.
Fixed
A skeleton placeholder announces itself once, not once per shape (#36). role="status" is an implicit polite live region, and every composite filled its own region with primitives that each carried one: seven regions for a SkeletonCard, ten for a pie SkeletonChart. SkeletonCard, SkeletonRow and SkeletonText also left their container unnamed while forwarding loadingLabel to every decorative child, so the region that should have been announced was anonymous.
Before you upgrade
Nothing breaks. Select is new. The skeleton change alters what a screen reader hears rather than what the DOM looks like, and a consumer that worked around the old behaviour with getAllByRole can go back to a plain getByRole.
Full changelog: v0.1.0-alpha.18...v0.1.0-alpha.19
v0.1.0-alpha.18
One Tooltip fix. No API change.
Fixed
The tooltip is placed in the same commit that opens it (#33). Placement was measured in a frame scheduled after mount, and until that frame ran the content sat in the DOM with visibility: hidden: painted nowhere, out of the accessibility tree, and unfindable by any query that respects that tree.
It measures in a layout effect now, so the position is set before the browser paints and the content is never exposed unplaced.
This surfaced as a flaky consumer test that focused a glossary term and looked for its tooltip. The package's own tests could not catch it: every one of them stubbed requestAnimationFrame to run synchronously, which is exactly the frame in question. The stubs are gone and one test now asserts the tooltip is in the accessibility tree in the same tick it opens.
Before you upgrade
A patch. Nothing renders differently; the tooltip simply reaches its position one frame earlier. If you stub requestAnimationFrame in tests around this component, you no longer need to.
Full changelog: v0.1.0-alpha.17...v0.1.0-alpha.18
v0.1.0-alpha.17
One new StatCard prop. Nothing renders differently unless you pass it.
Added
labelNode lets a stat label be a node (#31). It renders in place of the label text. label stays required and stays the card's accessible name, because a name derived from a node is whatever text falls out of it rather than something you wrote; pass the same words in both.
A stat label is not always plain text. The case this comes from is a glossary term whose definition appears on hover and focus, which is a node, and which no consumer could put here. The consumer that needed it kept a 339-line copy of this component to change one element, through an entire migration onto this package.
It follows TabItem's labelExtra: the same problem, solved the same way.
Before you upgrade
A minor addition. labelNode defaults to undefined and the label renders exactly as it did in 0.1.0-alpha.16.
Full changelog: v0.1.0-alpha.16...v0.1.0-alpha.17
v0.1.0-alpha.16
One new Tooltip prop. Nothing renders differently unless you pass it.
Added
toggleable makes the trigger a control (#29). With it, the trigger carries role="button" and an aria-expanded that tracks the content, and Enter and Space toggle it. Both keys are prevented from their defaults, since Space scrolls the page and Enter submits an enclosing form.
It is opt-in because a trigger whose content only supplements what is already on screen is not a control and should not announce itself as one. A glossary term is the opposite case: the definition is something a reader summons deliberately, and where there is no hover at all, activation is the only route to it.
Both continuum-hub and backend.ai-go have a glossary Term, both written before this package existed, and both built the same trigger contract around it: tabIndex={0}, role="button", aria-describedby, aria-expanded bound to the open state, Enter and Space toggling, Escape closing. The first of them lost that contract when it moved onto this component, which is what this prop is for.
Before you upgrade
A minor addition. toggleable defaults to false, and with it off the component behaves exactly as 0.1.0-alpha.15 did.
Full changelog: v0.1.0-alpha.15...v0.1.0-alpha.16
v0.1.0-alpha.15
Three Tooltip fixes. The component's docblock cites WCAG 2.1 SC 1.4.13; it now satisfies all three parts of that criterion, and it stays with its trigger when the page scrolls.
Fixed
Escape dismisses the tooltip (#26). Nothing did before, so a tooltip opened by hover could only be closed by moving the pointer off the trigger, even when it covered the thing being read. The listener is on the document, because a hover-opened tooltip leaves focus wherever it was.
The pointer can reach the content (#26). Leaving the trigger hid the tooltip at once. The content sits 8px away, so crossing to it put the pointer over the body in between, which closed it before it arrived: anything longer than a glance, or that a reader wanted to select, was unreachable. The hide is now deferred by 120ms, which covers the crossing.
The content takes pointer events (#26). .tooltip__content carried pointer-events: none, which made the previous fix meaningless in a browser: the element was never the target of a pointer event, so arriving on it fired nothing and selecting the text was impossible. Every behaviour test passed with it in place, because jsdom does not implement the property, so a stylesheet guard covers it now.
The tooltip stays anchored to its trigger (#27). Placement was measured once, when the tooltip opened. The content is position: fixed in a portal, so scrolling with the pointer or focus still on the trigger left the tooltip where the trigger had been, describing whatever scrolled into that spot; a resize left it off the edge. It re-measures on scroll and on resize now, listening in the capture phase since a scroll inside a container does not bubble.
All four were found while continuum-hub adopted this component in place of its own glossary tooltip, which handled Escape and tracked scrolling.
Before you upgrade
A patch. No API change, and nothing is laid out differently.
Two behaviours a consumer may notice: leaving the trigger now hides the tooltip 120ms later rather than instantly, and an open tooltip can take a pointer event that previously passed through to whatever sits under it.
Full changelog: v0.1.0-alpha.14...v0.1.0-alpha.15