Skip to content

Merge pingdotgg/t3code main into teleport tip.

MacroscopeApp / Macroscope - UI Consistency failed Aug 18, 2026 in 5m 22s

UI Consistency: 1 issue found

apps/web/src/components/teleport/TeleportOutButton.tsx — The new chat-header icon button is rendered via TooltipTrigger render={<Button …/>}. Button merges incoming props last, so the wrapper's data-slot="tooltip-trigger" replaces data-slot="button", and the custom-theme toolbar rules in index.css (html[data-theme-id] [data-chat-header] [data-slot="button"], [data-slot="menu-trigger"], [data-toolbar-control]) no longer match it. Under a custom theme the control renders with the default outline palette and no --toolbar-control-hover, unlike its sibling header controls. Suggested fix: add data-toolbar-control="", the same documented hook ProjectScriptsControl uses for tooltip-wrapped header buttons.

Previously flagged items were addressed in this revision: the teleport button now uses size="icon-xs" with primitive icon sizing and a cursor-not-allowed + aria-disabled busy treatment matching GitActionsControl, and the draft-hero import action restores cursor-pointer.

Details

Note

Your check run agent prompt is: .macroscope/check-run-agents/ui-consistency.md
More information about how Check Run Agents work can be found in our Help Center.

Files examined in scope: apps/web/src/components/teleport/TeleportOutButton.tsx, apps/web/src/components/chat/ChatHeader.tsx, apps/web/src/components/chat/DraftHeroHeadline.tsx, apps/web/src/components/chat/ChatComposer.tsx, apps/web/src/components/ChatView.tsx, apps/web/src/components/CommandPalette.tsx, apps/web/src/components/CommandPalette.logic.ts, apps/web/src/commandPaletteBus.ts, apps/web/src/lib/teleport.ts, apps/web/src/state/teleport.ts.

Checks performed:

  • Compared the new header control against OpenInPicker, ProjectScriptsControl, and GitActionsControl (all variant="outline", size="icon-xs" for icon halves) — geometry and variant match.
  • Traced the themed toolbar selectors in apps/web/src/index.css (lines 1305–1343) and Button's mergeProps(defaultProps, props) ordering to confirm the data-slot override, corroborated by the existing comment at ProjectScriptsControl.tsx:167-169.
  • Verified command-palette additions reuse ADDON_ICON_CLASS/ITEM_ICON_CLASS, the shared disabled-row renderer (CommandPaletteResults), the existing LoaderIcon + animate-spin convention, and existing title conventions ("New thread in...").
  • Verified the composer disabled/placeholder change keeps existing state precedence and that the draft-hero wrapper preserves pointer-events-auto and hero anchoring.

Not flagged: GitActionsControl's popover-wrapped disabled quick action has the same data-slot gap, but it is pre-existing and untouched by this PR.


🔍 Agent activity — 1 tool call

💭 I want to check whether the previously flagged issues with the TeleportOutButton busy state and DraftHeroHeadline button were addressed in the latest commit, so I'm pulling up the current files to verify. It looks like the prior findings are addressed—TeleportOutButton's sizing, the busy state cursor, and DraftHeroHeadline's pointer cursor all check out. I want to verify the busy state styling matches the convention used in GitActionsControl, and I should also look at what's new in CommandPalette. I'm checking whether the loading spinner in CommandPalette using ITEM_ICON_CLASS with animate-spin follows the same pattern as other spinners elsewhere in the palette, so I'll grep for how spinners are typically styled there. Good, the TeleportOutButton now matches the GitActionsControl aria-disabled pattern. Now I'm checking the other web-scope changes: ChatComposer's disabled prop, ChatView, CommandPalette's new items, commandPaletteBus, CommandPalette.logic, lib/teleport, and state/teleport. For ChatComposer, I'm looking at how the disabled condition now also checks whether the send is disabled due to being teleported out. Comparing the reason string directly to determine placeholder/disabled behavior feels a bit fragile, though it's more of a logic smell than a UI consistency issue. I want to look more closely at the surrounding context in ChatComposer to understand how this comparison is used. This behavior seems fine, though I should double check that noProviderAvailable and the disconnected phase aren't already part of the existing disabled list before the teleported addition. Now I want to look at the CommandPalette changes and compare the new status item against existing conventions for disabled items and keepOpen behavior, checking whether CommandPaletteActionItem actually supports a disabled state and how such items get rendered. I notice the helper functions got inserted in the middle of the import block, which is a bit of an odd code organization choice, though ES module hoisting makes it technically valid. Since my focus is UI consistency rather than code structure, I'll leave this out of scope and not flag it. Now I'm looking at the spinner icon using LoaderIcon with animate-spin, and checking whether the repo has an established convention for loading spinners elsewhere. The loading icon animation is fine as-is, and the minor template literal usage instead of cn isn't worth flagging. Now I want to check how CommandPaletteResults visually handles disabled items to see if there's an established convention. I notice importIntoProjectPaletteView wraps its items with enumerateCommandPaletteItems while nativeSessionsPaletteView doesn't, so I want to check what that function actually does—likely adding index-based shortcut numbering to the items. I'm checking whether the "new thread in" project list view uses enumeration for comparison, though flagging missing keyboard shortcut numbering on the sessions list feels like a stretch. I'll move on to look at the other in-scope web changes like ChatView, commandPaletteBus, and CommandPalette.logic. One possible UI-consistency issue: the "Import sessions..." action in CommandPalette uses ASCII "..." while the loading title uses the ellipsis character "…" elsewhere. I want to grep for ellipsis-style titles across CommandPalette to check consistency. I want to check how the TeleportOutButton fits into ChatHeader's layout, so I'm looking at the surrounding elements around lines 320-380 to make sure sizing stays consistent. I'm checking the ChatView and ChatComposer disabled-reason logic, plus the teleport re-export consistency between web and mobile. For the DraftHeroHeadline button, the author went with the minimal fix of restoring the pointer cursor rather than switching to the shared Button component, which matches the "at minimum" suggestion from the prior review. Now I'm verifying TeleportOutButton against the shared Button's styling conventions, confirming the busy-state classes and TooltipTrigger render patterns match existing precedents like GitActionsControl, and that the accessibility behavior for disabled/busy states is consistent. That all checks out, so I'm moving on to look at the CommandPalette's icon-only button details. I'm checking that the disabled import-sessions-status item is a safe no-op, that the new warning-type toast in ChatView is supported by the toast manager's styling, and that useLayoutEffect is already imported where needed in CommandPalette. I also confirm formatRelativeTimeLabel is properly imported for session descriptions, and I'm weighing whether coupling the composer's disabled placeholder logic to a specific string constant is worth flagging, though it seems more like an implementation detail than a UI-consistency issue. Looking at DraftHeroHeadline, I'm checking whether moving the centering classes from the h1 onto the wrapper div could affect pointer-events behavior or break any parent flex layout, but nothing seems to target the h1 specifically, so it should be safe. Let me check the container section in ChatView around lines 6380-6415 to look at pointer-events and layout behavior. I'm checking that the headline's absolute positioning still works correctly when adding the new button beneath it, since the block grows upward from its bottom anchor. The pointer-events-auto on the button is redundant given the parent already has it, but it matches the existing pattern used on the project selector, so I'll keep it consistent. The raw button duplicating Button variant="link" was already flagged in a prior review and the author chose the minimal fix, which was explicitly accepted then—re-flagging it now would just be repeating myself. I want to see what's actually new between the last reviewed commit and the current head before commenting further. Since I can't diff directly, I'll trust that the head content already reflects the prior fixes. Let me do one more pass over ChatView.tsx, checking the toast and sendDisabledReason regions for anything I might have missed. Everything checks out here. The composer disables correctly when teleported out, showing the placeholder as the disabled reason, and the tooltip on the send button should reflect that too. There's a minor edge case where the "messages loading" reason could take priority over the teleported-out reason, but that's an acceptable tradeoff. Let me verify the TeleportOutButton's icon sizing matches sibling controls, and confirm that opacity-64 is a valid theme utility since GitActionsControl already uses it. I also want to check whether the button variant (outline vs ghost) is consistent with other header controls like OpenInPicker and GitActionsControl. Interesting — header buttons wrapped in TooltipTrigger end up with data-toolbar-control="" because the tooltip wrapper replaces data-slot="button". I want to check that comment around ProjectScriptsControl lines 167-169 to see if there's styling tied to [data-toolbar-control] or [data-slot=button] that gets lost when a Button is rendered through TooltipTrigger — if so, TeleportOutButton, which lacks that attribute, could have a real styling inconsistency worth fixing. I'm noticing that TeleportOutButton renders its Button through TooltipTrigger's render prop, which swaps out the data-slot attribute the button normally has. That means under custom themes, the toolbar styling variables controlling background, border, and icon color likely won't apply to this button the way they do to its sibling controls. I should check tooltip.tsx to confirm whether TooltipTrigger actually overrides data-slot, and also verify the header container carries the data-chat-header attribute with TeleportOutButton nested inside it. I'm confirming the ChatHeader sits inside the data-chat-header wrapper, and now I'm working through how Base UI's render prop merges data-slot attributes between TooltipTrigger and Button to figure out which one ultimately wins. The existing comment in ProjectScriptsControl confirms TooltipTrigger's data-slot overrides Button's, meaning TeleportOutButton wrapped in a tooltip will lose its custom-theme toolbar styling — a real regression. Now I want to check whether GitActionsControl's quick-action button has the same wrapping issue, since it lacks the data-toolbar-control attribute that ProjectScriptsControl has, so I'm going to look at that section of the code. I'm noticing TeleportOutButton wraps its Button in TooltipTrigger, which likely strips the data-slot="button" attribute, meaning it won't pick up the toolbar control background under custom themes. The GitActionsControl case with PopoverTrigger might be a similar existing gap, but ProjectScriptsControl explicitly documents this hook pattern. The fix is to add data-toolbar-control="" to the Button, matching ProjectScriptsControl's approach. I want to verify Base UI's merging behavior for the render prop — whether the component's own data-slot attribute wins over the trigger's, since ProjectScriptsControl's comment explicitly notes the tooltip wrapper replaces data-slot="button", which seems like solid evidence for this codebase's behavior. If Button spreads incoming props after setting its own data-slot internally, the external data-slot="tooltip-trigger" would indeed override "button" — which matches what the comment claims. I should check Button's actual implementation to confirm this ordering. Since later props win in the merge, when TooltipTrigger clones the button with data-slot="tooltip-trigger", it overrides the original "button" slot value—confirming the earlier comment. This means TeleportOutButton ends up missing the themed toolbar styling that targets [data-slot="button"] and related selectors inside the chat header, which would break under a custom theme. I notice GitActionsControl has a similar gap in its disabled quick action, but that's pre-existing so I won't flag it. I'll post an inline review comment on TeleportOutButton.tsx suggesting adding data-toolbar-control="" to the Button props block around lines 78-82. Since this file is entirely new in the diff, all lines are on the RIGHT side, so the comment placement should work fine. I'll note this only affects custom themes but still creates a visible inconsistency in the same header row, so I'll flag it as a finding.

1. modify_pr — One finding: the new chat-header teleport button loses the themed toolbar control styling because the tooltip wrapper overwrites data-slot="button". See the inline comment for the one-attribute fix.


Agent Credits: 426 credits