Uh oh!
There was an error while loading. Please reload this page.
refactor(ui): hand the chat meta row back to Astryx primitives - #2358
Merged
Conversation
The row below a message reimplemented parts Astryx already ships, and each visible defect traced to one of those reimplementations. - The time was a hand-rolled `<small>` carrying a native `title` and `aria-hidden`, so the absolute reading was mouse-only and the visible one was hidden from assistive tech. It is now `Timestamp`, which is what `ChatMessageMetadata`'s own docs put in that slot: a semantic `<time datetime>` with a copyable hover card. `formatClockTime` had no other caller and is gone; its `hour12: false` was the app overriding a preference that belongs to the reader's system, so the hour cycle now follows the host locale (`14:32` in zh/en-GB/ja/de/fr, `2:32 PM` in en-US) and the hour loses its leading zero. - Footer icons were four separate `12` literals. They are now one named constant at 14 — the top of the range `--icon-size` reserves for "dense meta", and where the same position already sits most often across the app. A size has to be passed at all because Astryx's `sm` button bounds the icon slot at 16px without resizing the glyph: measured, an unsized lucide icon renders 16×24, squashed. - Tooltips wrapped each button in a `<Tooltip>` element. `Button` takes a `tooltip` prop and attaches the same behaviour through a hook, which is what its source recommends — the `display: contents` wrapper is gone and `aria-describedby` now resolves. - The hover gate sat on the row and so covered the time too, contrary to what the comment above it claimed. It moves to the footer slot, so the time stays put. Astryx's `·` separator between the slots is dropped outright: with the time always present and the actions fading in beside it, the two already read as separate and the bullet only adds a mark. - The row's top margin goes 4px → 6px. Its box is the 28px height of the buttons, not of the 12px time, so it sat tighter against the bubble than the margin suggested. Verified in Storybook against computed styles: `<time>` with a datetime, no `aria-hidden`, opacity 1 at rest; separator `display: none`; icons 14×14 in a 16px slot at the globally governed 1.75 stroke; buttons direct children of the meta row with `aria-describedby` set. A transparent action is still clickable. `pointer-events: none` was tried and reverted: it depends on the browser redoing hit-testing after the ancestor `:hover` restores the button, and the jump-and-stop case could not be reproduced on this surface to prove it safe.
This was referenced Aug 6, 2026
Astro-Han
marked this pull request as ready for review
August 7, 2026 03:35
Uh oh!
There was an error while loading. Please reload this page.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The row under a chat message reimplemented parts Astryx already ships, and every visible defect in it traced back to one of those reimplementations.
<small>carried a nativetitleandaria-hidden, so the absolute reading was mouse-only and the visible one was hidden from assistive tech. It is nowTimestamp— a semantic<time datetime>with a copyable hover card, and exactly whatChatMessageMetadata's own docs put in that slot.formatClockTimehad no other caller and is deleted.12literals became one named constant at14.--icon-sizereserves 12–14 for "dense meta" and this row is dense meta; 14 is also where the same position already sits most often across the app. A size must be passed at all because Astryx'ssmbutton bounds the icon slot at 16px without resizing the glyph — measured, an unsized lucide icon renders 16×24, squashed.<Tooltip>element.Buttontakes atooltipprop and attaches the same behaviour through a hook, which is what its source recommends. Thedisplay: contentswrapper is gone andaria-describedbynow resolves — previously it computed to nothing, which is why call sites carried hand-writtenaria-labelfallbacks.·separator is dropped rather than gated: with the time always present and the actions fading in beside it, the bullet added a mark without adding a distinction.Behaviour change worth knowing: the hour cycle now follows the host locale instead of a hardcoded
hour12: false. Most locales are unaffected (14:32in zh / en-GB / ja / de / fr); en-US renders2:32 PM. The hour also loses its leading zero (9:05, not09:05), which is whytabular-numsstays on that element.Refs #2359 — the icon sizing policy this lands against is unenforced repo-wide (145 hardcoded sizes across 11 values). This PR deliberately does not attempt that sweep.
Verification
npm run -w @maka/ui test— 442 passingnpm run -w @maka/ui typecheck,npm --workspace @maka/desktop run typecheck— cleannpm run lint,npm run format:check— cleannode scripts/check-dead-css.mjs --check,node scripts/check-a11y.mjs— cleanChecked against computed styles in Storybook (
Product/Shell Official AppShell → Native Conversation) rather than by eye:<time datetime="…">, noaria-hidden, opacity 1 at restdisplay: nonearia-describedbyresolvesmargin-top: 6pxReview focus
pointer-events: nonewas tried on the transparent actions — a transparent button still takes clicks — and reverted. It makes the pointer fall through to the ancestor whose:hoveris what restores the button, so being clickable again depends on the browser redoing hit-testing on a later mouse event. Continuous movement gets there; a pointer that jumps onto the button and stops could not be reproduced on this surface, so the fix could not be demonstrated safe. The pre-existing behaviour is left untouched and the reasoning is recorded in the CSS.