Skip to content

Releases

gpuicn v0.9.9

Choose a tag to compare

@github-actions github-actions released this 07 Nov 12:28
d350c43

gpuicn v0.9.9

Two fixes found while checking v0.9.8 in Matty. The runtime pins are
unchanged: GPUI Kit 0.9.0 on gpui-pre 0.3.11 and gpui-icons 0.6.0.

Fixed

  • An Attachment image sized with dimensions shrinks with a narrow
    column and keeps its aspect ratio, instead of running past the column's
    edge (matty#683). A message's content also lets wide children shrink
    with the row.
  • ShowMore's chevron takes the link color; it was drawn invisible.

gpuicn v0.9.8

Choose a tag to compare

@github-actions github-actions released this 07 Nov 11:45
9b280e1

gpuicn v0.9.8

Paper-cuts from Matty's jank review (matty#670): overlays close on Escape
even inside an app's own Escape shortcut, the lightbox closes on a click
around the image and stops blowing small images up, sidebar rows get a
label suffix for status emoji, and Markdown code blocks get a copy button.
Long content can collapse behind Show more. The runtime pins are
unchanged: GPUI Kit 0.9.0 on gpui-pre 0.3.11 and gpui-icons 0.6.0.

Added

  • SidebarItem::label_suffix puts content right after the label, such
    as a person's status emoji, where a hover-revealed options button never
    covers it. A long label truncates before it.
    label_suffix_tooltip shows the text behind it and is read after the
    label.
  • Code block copy button: every markdown() code block shows its
    language and a copy button that copies the raw code (no fences) and
    confirms with a check.
  • collapsible::ShowMore clips content taller than 600 px
    (max_height) behind a fade with Show more / Show less. It is
    uncontrolled, or controlled with expanded and on_toggle;
    fade_color matches the surface behind it.
  • LightboxImage::dimensions(width, height): with a known size, the
    lightbox fits large images down and shows small ones at their natural
    size.
  • primitives::dismiss::on_escape for your own overlays, the Dismiss
    action and the DISMISS_CONTEXT key context.
  • Strings: UiText::CopyCode, UiText::Copied.

Fixed

  • Escape closes dialogs, popovers, hover cards, menus and the lightbox
    when the app binds Escape in a context around them. GPUI runs key
    bindings before key listeners, so an app shortcut such as "mark read"
    used to take the key first. Escape is now the Dismiss action, bound
    in the overlay's own, deeper key context.
  • The lightbox closes on a click on the dark area around a fitted image.

Upgrading

LightboxImage has a new public field, size; code that builds it with
a struct literal adds size: None. Copied components pick these changes
up with gpuicn diff.

gpuicn v0.9.7

Choose a tag to compare

@github-actions github-actions released this 05 Nov 11:34
59c4d58

gpuicn v0.9.7

Matty's request for translated and right-to-left interfaces (#143, for
matty#225): every built-in string can be replaced without forking a
component, and one setting lays the whole library out right to left. Also a
one-line Sortable bookmarks bar with its own gap (#145), pasted one-time
codes (#147), menus that rebuild from their own clicks (#148) and animated
GIFs (#149). The
runtime pins are unchanged: GPUI Kit 0.9.0 on gpui-pre 0.3.11 and
gpui-icons 0.6.0.

Added

  • Strings (theme::locale): UiText names each string a component
    writes for you, including the emoji picker's search, section, category
    and skin tone names, "Close" on dialogs, drawers, toasts and the
    lightbox, empty and loading states, the calendar's months, weekdays and
    dates, AM/PM, the text edit menu, and accessible labels and
    announcements. locale::set_strings(cx, |text| ...) returns a
    translation or None for English; UiText::key() is a stable id for a
    catalog and UiText::english() the default.
  • Direction: locale::set_direction(cx, Direction::Rtl) mirrors rows,
    start and end paddings, insets, borders and corners; flips chevrons and
    arrows; opens menus, submenus, popovers, date pickers and composer
    suggestions from the mirrored edge; moves left drawers, sidebars and
    toast stacks to the right; aligns single-line inputs, popovers and
    tooltips to the start; and makes Left and Right (with their word and
    selection variants) follow the reading direction in inputs, menus,
    menubars, tabs, toolbars, toggle groups, the calendar, the emoji picker,
    the lightbox and sortable lists. theme.direction carries it and
    survives UiTheme::set and UiTheme::switch.
  • Bidi isolation: locale::isolate(text) wraps a name in
    first-strong isolates so mixed-script text keeps its order; a quoted
    message's "Originally posted in" uses it.
  • Helpers: DirectionalStyled (flex_row_in, mirror_row,
    padding_start/end, inset_start/end, border_start_1,
    rounded_start/end, ...) and Direction::{placement, align, anchor, icon, logical_key} for your own views. DrawerSide, SidebarSide and
    ToastPlacement gain physical(direction).
  • Sortable: wrap(false) keeps a horizontal list on one line at its
    content width, so a bookmarks bar scrolls sideways instead of wrapping,
    and gap(px) sets the space between items, with the drop line centred in
    it (#145).
  • OtpField paste: Cmd/Ctrl+V, or a Paste action from the Edit menu,
    fills the cells from the clipboard's digits, ignoring spaces, dashes and
    other text. A full code replaces the value and a partial one continues
    it; the state emits Change, then Complete when the last cell fills.
    otp_field::paste_code(&state, text, window, cx) does the same from your
    own code (#147).
  • Animated pictures: primitives::image(source) is an img with an id
    derived from its source, which GPUI needs before it advances GIF and WebP
    frames. clipped_image, round_image, attachments, avatars, custom
    emoji in Markdown, messages and the emoji picker, Markdown pictures and
    the lightbox use it, so animated pictures play instead of showing their
    first frame. Reduced motion still holds them still (#149).
  • Site: ?dir=rtl on a component page previews it right to left.

See Strings and layout direction.

Fixed

  • MenuItem::on_click handlers run after the menu closes and its state
    update returns, so a handler can call MenuState::set_items, directly or
    through your own entity, to redraw radio items. It used to panic with a
    double lease (#148).

Changed

  • Disabled calendar days, command items and sidebar items read
    ", Unavailable", matching the other unavailable controls, instead of
    ", unavailable".

Not mirrored yet

The carousel track, slider and multi-line text areas belong to GPUI Kit and
stay left to right. Shortcut key caps and the time field's segment order
stay left to right on purpose.

Compatibility

UiTheme gains a public direction field, so code that builds UiTheme
with a struct literal needs direction: Direction::Ltr. Nothing else
changes for left-to-right apps: every default string is the same English as
before.

Upgrading

cargo install gpuicn-cli --version 0.9.7 --locked
gpuicn update --to 0.9.7

Crate users: cargo update -p gpuicn.

gpuicn v0.9.6

Choose a tag to compare

@github-actions github-actions released this 05 Nov 04:16
c42360d

gpuicn v0.9.6

Fourteen requests from Matty: five new components for forms and scheduling,
interactive attachments, spelling, async selects, theme tokens and
multi-message copy. The runtime pins are unchanged: GPUI Kit 0.9.0 on
gpui-pre 0.3.11 and gpui-icons 0.6.0.

New components

  • Alert: an inline callout with an icon, title, description and actions,
    in Default, Destructive, Warning, Info and Success. Destructive and warning
    alerts are announced (#135).
  • Avatar Group: overlapping avatars with a +N chip, a hover tooltip and
    one accessible name that lists everyone (#140).
  • Calendar: a month grid with keyboard navigation, limits, today and a
    configurable first weekday, over a small CalendarDate type (#140).
  • Date Picker: an outline trigger that opens a Calendar (#140).
  • Date Time Picker: a calendar and a keyboard time field in one popover,
    with a 12- or 24-hour clock from the locale and date-and-time limits (#138).

Added

  • Avatar: a status dot on a resized avatar scales with it, and
    status_size sets it (#127).
  • Button: tint(color) derives fill, hover and readable text from one
    integration color (#134).
  • Command: CommandItem::description adds muted trailing text (#133).
  • Composer: triggers inside inline code and fenced blocks are ignored
    (#129); open_suggestions(range, items) opens the popup for a range the
    app chose, and accepting it emits ComposerEvent::AcceptRange (#136);
    set_misspellings underlines words (#139).
  • Field: Field::from_control takes a Checkbox or a RadioGroup (#135).
  • Input: focused inputs and textareas take an opaque fill (#135);
    Textarea::misspellings draws wavy underlines and a native suggestions
    menu (#139).
  • Markdown: MarkdownImages::placeholder shows a click-to-load
    ImagePlaceholder, and image_size reserves an image's own box (#131).
  • Message: copy_prefix makes a copy across messages read one line per
    message, such as Ada [12:24]: Thanks!; a copy inside one message is
    unchanged. selection_group does the same for other regions (#128).
  • MessageEmbed: action adds buttons and selects inside the card (#134).
  • Select: set_items replaces items while open for async results,
    keeping the query, value and highlight; set_loading shows a status row
    (#141).
  • Sidebar: sidebar_mention_badge, and group labels use the new muted
    token (#132).
  • Sortable: horizontal() for rows of chips, with a vertical drop line
    and Alt+Shift+Left and Right (#137).
  • Theme: optional link, mention_highlight,
    mention_highlight_foreground, new_messages, sidebar_muted_foreground,
    sidebar_badge and sidebar_badge_foreground tokens that fall back to
    their base tokens, settable from shadcn CSS; UiTheme::code_theme picks a
    code block palette (GitHub, Monokai, Solarized); UiTheme::opaque (#132).

Compatibility

UiColors and CommandItem gain public fields and ComposerEvent gains a
variant. Code that builds UiColors or CommandItem with a struct literal,
or matches ComposerEvent without a wildcard, needs the new fields (they
are None) or arm. FieldControl::field_focus_handle now has a default.

Upgrading

cargo install gpuicn-cli --version 0.9.6 --locked
gpuicn update --to 0.9.6

Crate users: cargo update -p gpuicn.

gpuicn v0.9.5

Choose a tag to compare

@github-actions github-actions released this 04 Nov 19:16
bfd7767

gpuicn v0.9.5

Two more requests from Matty: a clickable author name on messages, and toasts
that tell the app when they leave. Everything is additive; the runtime pins
are unchanged: GPUI Kit 0.9.0 on gpui-pre 0.3.11 and gpui-icons 0.6.0.

Added

  • Message: the author name can open something, such as a profile card
    (#123).
    • on_author_click(handler) draws the name as a link-styled button that
      takes focus with Tab, runs on click, Enter or Space and underlines on
      hover. The handler gets the click and the name's bounds in window
      coordinates, to anchor a popover.
    • author_element(element) puts your own element in place of the name,
      such as the hover_popover trigger you already wrap around the avatar.
      It inherits the name's weight, size and color.
    • Both work in standard and compact density.
  • Toast: the app can follow a notification's life (#122).
    • Notice::on_dismiss(handler) runs once when a notice starts to leave,
      with a NoticeDismissal: Action, Cancel (such as "Later"), Close,
      Timeout, Dismissed (the app called dismiss) or Replaced (the app
      pushed the same ID again). NoticeDismissal::by_reader is true for Cancel
      and Close. The handler runs after the current update, so it may push
      again.
    • ToastState::contains(id) says whether a notice is queued or on screen
      and not already leaving.
    • ToastState::set_placement(ToastPlacement) moves the stack to any corner
      or the middle of the top or bottom edge (bottom left stays the default),
      and set_inset(horizontal, vertical) sets its distance from the window
      edges, such as to clear a composer.

Upgrading

cargo install gpuicn-cli --version 0.9.5 --locked
gpuicn update --to 0.9.5

Crate users: cargo update -p gpuicn.

gpuicn v0.9.4

Choose a tag to compare

@github-actions github-actions released this 04 Nov 17:56
ec47ca1

gpuicn v0.9.4

Six requests from Matty: presence dots on avatars, menus that fit the window,
hover profile cards, quoted posts, accessible-name audits and sortable lists.
Everything is additive; the runtime pins are unchanged: GPUI Kit 0.9.0 on
gpui-pre 0.3.11 and gpui-icons 0.6.0.

Added

  • Avatar: status(AvatarStatus) draws a presence dot over the
    bottom-right corner, sized to the avatar (8, 10 or 12px), in a ring of the
    surface color (#115).
    • Online, Away and Dnd use the success, warning and destructive
      tokens; Offline is a hollow ring; Custom { color, label } covers the
      rest. Set the tokens in your theme to restyle every dot.
    • ring_color matches the ring to the surface, such as colors.sidebar.
    • The status joins the accessible name: "Ana Lopez, away".
  • Popover: hover_popover(id, label) for profile cards (#118).
    • The trigger is one focusable button named label, usable on an avatar
      or an inline name; trigger_style_with restyles it.
    • Resting the pointer opens it after 500ms without moving focus, and the
      pointer can move into the card; it closes 300ms after the pointer leaves
      (open_on_hover sets both delays).
    • Click, Enter or Space opens it with focus inside, and it stays until
      Escape (which returns focus to the trigger), a click outside or the
      trigger again.
  • Embed: QuotedMessage for pasted permalinks and forwards (#119): the
    author's avatar, name and time with a Jump link, "Originally posted in
    {channel}", a body clamped to four lines with "Show more", and an optional
    attachment strip. It takes density like the other embeds and is named
    "Quoted message from {author}".
  • Sortable, a new component (#121): Sortable, SortableGroup and
    SortableRow.
    • Dragging a row shows a copy of it at reduced opacity and a line where it
      will land; an empty or collapsed group highlights and takes the row at
      its end.
    • With focus in a row, Alt+Shift+Up and Down move it one place, across
      groups at either end, and announce the new position.
    • reorder_groups(true) lets headers drag and take the same keys.
    • on_reorder reports a SortableMove; SortableMove::apply and
      move_group apply moves to your data. Nothing animates.
  • Accessibility audits (#120): with the new test-support feature,
    gpuicn::audit::unnamed_controls(window) lists interactive elements with
    no accessible name in the last frame, and A11yAuditOverlay outlines them
    in the destructive color and logs their paths. Buttons, toggles,
    checkboxes, switches, selects, menus, tabs, inputs, the composer, sidebar
    rows and dialog triggers already registered; this release adds the
    remaining interactive parts.

Changed

  • Menu panels are as tall as the window allows before they scroll, on
    whichever side of the trigger has more room; context menus and submenus
    use the window height. Submenus open after 200ms of hover, and a sibling
    row closes them (#117).

Upgrading

cargo install gpuicn-cli --version 0.9.4 --locked
gpuicn update --to 0.9.4

Crate users: cargo update -p gpuicn. For the audit, enable the feature in
your dev-dependencies: gpuicn = { version = "0.9.4", features = ["test-support"] }.

gpuicn v0.9.3

Choose a tag to compare

@github-actions github-actions released this 04 Nov 12:24
39065d3

gpuicn v0.9.3

A request from Matty: embed cards can hold a click-to-load placeholder where
their image goes, for applications that ask before loading remote images.
The change is additive; the runtime pins are unchanged: GPUI Kit 0.9.0 on
gpui-pre 0.3.11 and gpui-icons 0.6.0.

Added

  • Embed: ImagePlaceholder, passed to LinkPreview::image_placeholder,
    MessageEmbed::image_placeholder or MessageEmbed::thumbnail_placeholder
    in place of the image (#111).
    • It takes the box the image would take, so nothing moves when the image
      loads: the card's inner width at the pixel size from .size(w, h), or
      16:9 when the size is unknown, large below the text or a thumbnail on the
      right by the same rules as image.
    • A muted surface shows the image icon, "Load image" and the host, and
      fills with the accent color on hover.
    • It is a button named "Load image from {host}" with the focus ring. Click,
      Enter or Space runs on_load once; fetch the image there and pass it
      through image on the next render. label and aria_label replace the
      text, such as for a translation.

Embed, light
Embed, dark

Upgrading

cargo install gpuicn-cli --version 0.9.3 --locked
gpuicn update --to 0.9.3

Crate users: cargo update -p gpuicn.

gpuicn v0.9.2

Choose a tag to compare

@github-actions github-actions released this 04 Nov 07:21
63e16eb

gpuicn v0.9.2

Two requests from Matty: a new Embed component for cards under a chat
message, and dialogs taller than the window now scroll under the pointer.
Every change is additive; the runtime pins are unchanged: GPUI Kit 0.9.0 on
gpui-pre 0.3.11 and gpui-icons 0.6.0.

Added

  • Embed (gpuicn add embed): two cards for what a chat server attaches to
    a post (#108).
    • LinkPreview is an Open Graph preview: a muted site name, a title that
      wraps to two lines and opens the link, a description clamped to three
      lines, and an image. The image is large below the text, or a thumbnail
      on the right when it is narrower than 150px or roughly square. The caller
      passes its pixel size, so the card holds the box before the bytes load.
      on_toggle adds a "Collapse preview" / "Expand preview" chevron that
      hides the image, and on_remove adds a "Remove preview" button.
    • MessageEmbed is the integration attachment: a colored bar (any color,
      a hex string, or good, warning and danger), pretext, an author line
      with an icon, a title, a body slot for your Markdown, a fields grid with
      short fields two to a row, an image, a thumbnail and a footer with an
      icon and a time.
    • Both follow MessageDensity, read every color from the theme, and are
      groups named by their title. Linked titles take focus and open on Enter.

Embed, light
Embed, dark

Fixed

  • Dialog: a dialog taller than the window scrolls with the wheel over its
    surface. dialog_popup used occlude(), which hid the wheel from the
    dialog's scrolling viewport, so the content stayed clipped. It now uses
    block_mouse_except_scroll(): clicks and hover still stop at the surface,
    and the backdrop still keeps the wheel from the page behind. If you built
    your own surface for dialog with occlude(), switch it the same way
    (#109).

Upgrading

cargo install gpuicn-cli --version 0.9.2 --locked
gpuicn update --to 0.9.2

Crate users: cargo update -p gpuicn.

gpuicn v0.9.1

Choose a tag to compare

@github-actions github-actions released this 04 Nov 04:04
2e21f99

gpuicn v0.9.1

Seven additions Matty asked for while building its chat client. Every change
is additive: existing code compiles and draws as before, and installed source
from v0.9.0 changes only in the files below (gpuicn diff lists them). The
runtime pins are unchanged: GPUI Kit 0.9.0 on gpui-pre 0.3.11 and gpui-icons
0.6.0.

Added

  • Message: timestamp_tooltip shows the full date and time when the
    reader hovers the time, on header, continuation and compact rows (#94).
    on_gutter_click makes the avatar column a click target for selecting the
    row, while clicks on the body stay free for text selection and links (#98).
  • Toast: Notice::action(label, handler) and Notice::cancel(label) add
    buttons to a notification. Pressing either dismisses it; the action runs its
    handler first. Tab reaches them before the close button, and hovering the
    stack pauses the timeout as before (#95).
  • MessageList: on_jump hands the "Jump to latest" pill to the
    application, which can load the newest page after a jump into the past
    instead of scrolling to the loaded end. show_jump(true) keeps the pill
    visible at the loaded end of such a window (#97).
  • Attachment: dimensions(width, height) sizes an image thumbnail from the
    file's metadata, keeping its aspect ratio inside max_size (360 × 240 by
    default), and holds that box with a muted fill while the image loads, so the
    transcript does not jump (#99).
  • Sidebar: roving_focus(true) makes the navigation rows one tab stop.
    Tab lands on the focused or selected row and the next Tab leaves; Up and
    Down move between rows (wrapping, skipping disabled ones), Home and End jump
    to the ends, and the focused row scrolls into view (#100).
  • Composer: ComposerState::set_max_rows and max_rows change the growth
    cap without rebuilding the state, and Composer::max_height(px) caps the
    text box in pixels, for example at 40% of the window, following resizes and
    keeping the draft (#101).
  • ScrollArea: track_scroll(&ScrollHandle) shares the scroll position
    with the caller.

Upgrading

cargo install gpuicn-cli --version 0.9.1 --locked
gpuicn update --to 0.9.1

Crate users: cargo update -p gpuicn.

gpuicn v0.9.0

Choose a tag to compare

@github-actions github-actions released this 03 Nov 22:54
7329d1e

gpuicn v0.9.0

The consistency release. Every component now reads every color, size, radius,
shadow and duration from the theme through one set of primitives, a lint keeps
it that way, and setting up a themed app is one command. The runtime pins are
unchanged: GPUI Kit 0.9.0 on gpui-pre 0.3.11 and gpui-icons 0.6.0.

One-command setup

cargo install gpuicn-cli --version 0.9.0 --locked
gpuicn new my-app --base-color zinc --appearance dark
cd my-app && cargo run
  • ui::app::run: the starter main.rs is a window title, a theme pair and
    a root view. app::run(AppConfig::new("My App").themes(light, dark), |_, _| Root)
    opens the platform with the Lucide assets, loads the bundled Geist fonts,
    installs the pair, follows the operating system's appearance and opens the
    window. AppConfig::install does the same without a window.
  • Theme pairs: UiTheme::set_pair, UiTheme::set_appearance with
    Appearance::{Light, Dark, System}, and theme::follow_system.
  • shadcn's base colors: gpuicn init writes assets/theme.css from
    neutral, stone, zinc, mauve, olive, mist or taupe and generates
    src/ui/app_theme.rs. gpuicn theme set --base-color stone --radius 0.5rem --appearance dark changes it; gpuicn theme import theme.css takes a theme
    from the shadcn theme editor or tweakcn; gpuicn theme preview prints every
    token.
  • gpuicn update moves an app to a release (config, Cargo pins, fonts,
    theme files, then status); gpuicn doctor checks everything against
    the CLI's release and prints a fix per finding; gpuicn remove --unused
    deletes components your code never names.
  • gpuicn.toml is version 2 with a [theme] table. Version 1 files still load.

Consistent by construction

  • Primitives in theme::primitives: text, icon, focus, disabled,
    surface, control, clipped_image, dismiss, hover_reveal_in_group.
    Every component uses them; the registry lint in crates/ui/tests fails a
    change that reintroduces a raw color, text size, opacity, mode branch,
    popover background, hover state, key glyph or pub(crate) item.
  • Focus is one 3px outer ring in ring at 50%, shown through
    focus_visible, on every control.
  • Tokens: status colors (success, warning, info, with foregrounds),
    destructive_foreground, typography (xs to xl with line heights),
    breakpoints, and derived control() colors per mode. Every GPUI Kit
    component color follows a token (a test enumerates them).
  • Motion: transition_with and presence_with over the theme durations,
    UiEasing::Emphasized; dialogs fade in and no longer scroll themselves.
  • Input and Textarea share one InputCore; Message hover actions use a group
    instead of state.

Reliability

  • MessageList has a position-based scrollbar (MessageListScrollbar)
    that estimates unmeasured rows from the measured average, so the thumb
    tracks position in long histories instead of jumping as rows are measured
    (#83). Pass scrollbar_handle to share one across re-renders.
  • Toast schedules on deadlines instead of polling every 50ms.
  • Tooltip installs one Escape interceptor for the application.
  • Every component is drawn in both themes by a test; interactive ones have
    behavior tests in crates/ui/tests/catalog.rs.

Message

  • density(MessageDensity::Compact): one line per post, the time always in
    the gutter, the name inline, half the row padding (#88).

For contributors

  • One preview file per component under site/src/previews/;
    cargo xtask new-component <name> scaffolds a component everywhere the
    catalog expects one. docs/design.md states the rules.
  • Releases ship catalog-screenshots-<tag>.zip, the light and dark sheet of
    every preview, and docs/screenshots/v0.9.0 holds this release's.

Breaking changes

  • UiTheme::shadows entries are Arc<[BoxShadow]>; call .to_vec() where a
    Vec is needed.
  • sidebar_is_mobile(window, cx) takes the window.
  • UiColors::slot is public but #[doc(hidden)].

Upgrading

cargo install gpuicn-cli --version 0.9.0 --locked --force
gpuicn update --to 0.9.0     # config, pins, fonts, theme files; then `gpuicn diff`
gpuicn update --overwrite    # replace installed files once your edits are reviewed
gpuicn doctor

Apps that keep their own main.rs can switch to ui::app::run or keep
calling ui::theme::init(cx); doctor accepts both.