fix(web): stop vimium hinting icons inside buttons (#13994)

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Jamison LahmanandClaude Opus 5 authored and GitHub committed 2026-08-14 20:33:28 +00:00
1 parent 31fe91f3dc
commit e6db02c74a
18 files changed
+110 -115

No files matched your search

@@ -1,8 +1,8 @@
.opal-button-chevron {
.opal-chevron {
transition: rotate 200ms ease;
}
.interactive[data-interaction="hover"] .opal-button-chevron,
.interactive[data-interaction="active"] .opal-button-chevron {
.interactive[data-interaction="hover"] .opal-chevron,
.interactive[data-interaction="active"] .opal-chevron {
rotate: -180deg;
}
@@ -12,10 +12,7 @@ import { cn } from "@opal/utils";
*/
function ChevronIcon({ className, ...props }: IconProps) {
return (
<SvgChevronDownSmall
className={cn(className, "opal-button-chevron")}
{...props}
/>
<SvgChevronDownSmall className={cn(className, "opal-chevron")} {...props} />
);
}
@@ -66,9 +66,7 @@ function LinkButton({
}: LinkButtonProps) {
const inner = (
<>
<span className="opal-link-button-label font-secondary-body">
{children}
</span>
<span className="opal-link-label font-secondary-body">{children}</span>
{/* The glyph is aria-hidden, so new-window behavior needs a spoken cue. */}
{target === "_blank" && (
<span className="sr-only">(opens in new tab)</span>
@@ -28,6 +28,6 @@
/* `font-secondary-body` is a plain CSS class defined in globals.css (not a
Tailwind utility), so `@apply` can't consume it — other Opal components
attach it via `className` on the JSX element, and we do the same here. */
.opal-link-button-label {
.opal-link-label {
@apply underline;
}
@@ -28,10 +28,10 @@ Use SelectButton for general-purpose stateful toggles. Use `OpenButton` for popo
```
Interactive.Stateful <- variant, state, interaction, disabled, onClick
└─ Interactive.Container <- height, rounding, padding (from `size`)
└─ div.opal-select-button.interactive-foreground
└─ div.opal-select-content.interactive-foreground
├─ Icon? (interactive-foreground-icon)
├─ [Foldable]? (wraps label + rightIcon when foldable)
│ ├─ <span> .opal-select-button-label
│ ├─ <span> .opal-select-content-label
│ └─ RightIcon?
└─ <span>? / RightIcon? (non-foldable)
```
@@ -102,7 +102,7 @@ function SelectButton({
>
<div
className={cn(
"opal-select-button",
"opal-select-content",
foldable && "interactive-foldable-host"
)}
>
@@ -2,6 +2,6 @@
/* SelectButton — layout only; colors handled by Interactive.Stateful */
.opal-select-button {
.opal-select-content {
@apply flex flex-row items-center gap-1;
}
@@ -15,7 +15,7 @@ slots).
```
Interactive.Stateless <- always variant="default" / prominence="tertiary"; disabled, href, onClick
└─ <Link> / <button> <- .opal-text-button.interactive-foreground, no height/rounding/padding/border
└─ <Link> / <button> <- .opal-text-label.interactive-foreground, no height/rounding/padding/border
└─ <Text font={font} color="inherit" as="p">
```
@@ -81,12 +81,12 @@ function TextButton({
href={(disabled ? undefined : href) as Route}
target={target}
rel={target === "_blank" ? "noopener noreferrer" : undefined}
className="opal-text-button interactive-foreground"
className="opal-text-label interactive-foreground"
>
{label}
</Link>
) : (
<div className="opal-text-button interactive-foreground">{label}</div>
<div className="opal-text-label interactive-foreground">{label}</div>
)}
</Interactive.Stateless>
);
@@ -14,6 +14,6 @@
plain `Text` node with hover/active color animation.
============================================================================ */
.opal-text-button {
.opal-text-label {
@apply bg-transparent;
}
@@ -1,6 +1,6 @@
/* AttachmentButton styles */
.attachment-button {
.attachment-item {
display: flex;
flex-direction: row;
width: 100%;
@@ -10,15 +10,15 @@
gap: 0.5rem;
}
.attachment-button:hover {
.attachment-item:hover {
background-color: var(--background-tint-02);
}
.attachment-button[data-state="selected"] {
.attachment-item[data-state="selected"] {
background-color: var(--action-selection-01);
}
.attachment-button__content {
.attachment-item__content {
flex: 1;
display: flex;
flex-direction: row;
@@ -26,7 +26,7 @@
min-width: 0;
}
.attachment-button__icon-wrapper {
.attachment-item__icon-wrapper {
height: 100%;
aspect-ratio: 1;
background-color: var(--background-tint-01);
@@ -38,17 +38,17 @@
flex-shrink: 0;
}
.attachment-button__icon {
.attachment-item__icon {
height: 1rem;
width: 1rem;
stroke: var(--text-02);
}
.attachment-button[data-state="processing"] .attachment-button__icon {
.attachment-item[data-state="processing"] .attachment-item__icon {
stroke: var(--text-01);
}
.attachment-button__text-container {
.attachment-item__text-container {
display: flex;
flex-direction: column;
align-items: flex-start;
@@ -57,7 +57,7 @@
flex: 1;
}
.attachment-button__title-row {
.attachment-item__title-row {
display: flex;
flex-direction: row;
align-items: center;
@@ -66,23 +66,23 @@
min-width: 0;
}
.attachment-button__title-wrapper {
.attachment-item__title-wrapper {
max-width: 70%;
min-width: 0;
flex-shrink: 1;
overflow: hidden;
}
.attachment-button__view-button {
.attachment-item__view {
flex-shrink: 0;
visibility: hidden;
}
.attachment-button:hover .attachment-button__view-button {
.attachment-item:hover .attachment-item__view {
visibility: visible;
}
.attachment-button__actions {
.attachment-item__actions {
display: flex;
flex-direction: row;
align-self: stretch;
@@ -93,10 +93,10 @@
flex-shrink: 0;
}
.attachment-button__action-button {
.attachment-item__action {
visibility: hidden;
}
.attachment-button:hover .attachment-button__action-button {
.attachment-item:hover .attachment-item__action {
visibility: visible;
}
+14 -14
View File
@@ -1,6 +1,6 @@
/* LineItem Button Variants */
/* Hover styles are disabled when keyboard navigation is active (data-keyboard-nav on parent) */
.line-item-button-main {
.line-item-row-main {
@apply bg-transparent hover:bg-background-tint-02;
[data-keyboard-nav="true"] &:hover {
@@ -8,7 +8,7 @@
}
}
.line-item-button-main-emphasized {
.line-item-row-main-emphasized {
@apply bg-transparent hover:bg-background-tint-02;
[data-keyboard-nav="true"] &:hover {
@@ -25,7 +25,7 @@
}
}
.line-item-button-strikethrough {
.line-item-row-strikethrough {
@apply bg-transparent hover:bg-background-tint-02;
[data-keyboard-nav="true"] &:hover {
@@ -33,7 +33,7 @@
}
}
.line-item-button-strikethrough-emphasized {
.line-item-row-strikethrough-emphasized {
@apply bg-transparent hover:bg-background-tint-02;
[data-keyboard-nav="true"] &:hover {
@@ -41,15 +41,15 @@
}
}
.line-item-button-disabled {
.line-item-row-disabled {
@apply bg-transparent cursor-not-allowed;
}
.line-item-button-disabled-emphasized {
.line-item-row-disabled-emphasized {
@apply bg-transparent cursor-not-allowed;
}
.line-item-button-danger {
.line-item-row-danger {
@apply bg-transparent hover:bg-background-tint-02;
[data-keyboard-nav="true"] &:hover {
@@ -57,7 +57,7 @@
}
}
.line-item-button-danger-emphasized {
.line-item-row-danger-emphasized {
@apply bg-transparent hover:bg-background-tint-02;
[data-keyboard-nav="true"] &:hover {
@@ -75,7 +75,7 @@
}
/* Action Variant - same background behavior as main */
.line-item-button-action {
.line-item-row-action {
@apply bg-transparent hover:bg-background-tint-02;
[data-keyboard-nav="true"] &:hover {
@@ -83,7 +83,7 @@
}
}
.line-item-button-action-emphasized {
.line-item-row-action-emphasized {
@apply bg-transparent hover:bg-background-tint-02;
[data-keyboard-nav="true"] &:hover {
@@ -101,7 +101,7 @@
}
/* Muted Variant - subdued styling for less prominent items */
.line-item-button-muted {
.line-item-row-muted {
@apply bg-transparent hover:bg-background-tint-02;
[data-keyboard-nav="true"] &:hover {
@@ -109,7 +109,7 @@
}
}
.line-item-button-muted-emphasized {
.line-item-row-muted-emphasized {
@apply bg-transparent hover:bg-background-tint-02;
[data-keyboard-nav="true"] &:hover {
@@ -127,7 +127,7 @@
}
/* Skeleton Variant - dashed border placeholder style */
.line-item-button-skeleton {
.line-item-row-skeleton {
@apply bg-transparent border border-dashed border-border-01 hover:bg-background-tint-01;
[data-keyboard-nav="true"] &:hover {
@@ -135,7 +135,7 @@
}
}
.line-item-button-skeleton-emphasized {
.line-item-row-skeleton-emphasized {
@apply bg-transparent border border-dashed border-border-01 hover:bg-background-tint-02;
[data-keyboard-nav="true"] &:hover {
+1 -1
View File
@@ -1,5 +1,5 @@
@import "@onyx-ai/opal/root.css";
@import "./css/attachment-button.css" layer(base);
@import "./css/attachment-item.css" layer(base);
@import "./css/button.css" layer(base);
@import "./css/content-editable.css" layer(base);
@import "./css/card.css" layer(base);
+2 -2
View File
@@ -37,10 +37,10 @@ function AttachmentItemLayout({
<div className={cn("h-9 aspect-square rounded-08 shrink-0")}>
<Section>
<div
className="attachment-button__icon-wrapper"
className="attachment-item__icon-wrapper"
data-testid="attachment-item-icon-wrapper"
>
<Icon className="attachment-button__icon" />
<Icon className="attachment-item__icon" />
</div>
</Section>
</div>
@@ -110,21 +110,21 @@ export default function AttachmentButton({
return (
<button
type="button"
className="attachment-button"
className="attachment-item"
data-state={state}
{...props}
>
<div className="attachment-button__content">
<div className="attachment-button__icon-wrapper">
<div className="attachment-item__content">
<div className="attachment-item__icon-wrapper">
{selected ? (
<Checkbox checked />
) : (
<Icon className="attachment-button__icon" />
<Icon className="attachment-item__icon" />
)}
</div>
<div className="attachment-button__text-container">
<div className="attachment-button__title-row">
<div className="attachment-button__title-wrapper">
<div className="attachment-item__text-container">
<div className="attachment-item__title-row">
<div className="attachment-item__title-wrapper">
<Truncated mainUiMuted text04 nowrap>
{children}
</Truncated>
@@ -135,7 +135,7 @@ export default function AttachmentButton({
icon={SvgExternalLink}
onClick={noProp(onView)}
internal
className="attachment-button__view-button"
className="attachment-item__view"
/>
)}
</div>
@@ -147,14 +147,14 @@ export default function AttachmentButton({
</div>
</div>
<div className="attachment-button__actions">
<div className="attachment-item__actions">
{rightText && (
<Text as="p" secondaryBody text03>
{rightText}
</Text>
)}
{actionIcon && onAction && (
<div className="attachment-button__action-button">
<div className="attachment-item__action">
<Button
icon={actionIcon}
onClick={noProp(onAction)}
@@ -160,36 +160,36 @@ const iconClasses = (transient: boolean | undefined) =>
secondary: {
enabled: [
"stroke-text-03",
"group-hover/IconButton:stroke-text-04",
"group-hover/IconAction:stroke-text-04",
transient && "stroke-text-04",
"group-active/IconButton:stroke-text-05",
"group-active/IconAction:stroke-text-05",
],
disabled: ["stroke-text-01"],
},
tertiary: {
enabled: [
"stroke-text-03",
"group-hover/IconButton:stroke-text-04",
"group-hover/IconAction:stroke-text-04",
transient && "stroke-text-04",
"group-active/IconButton:stroke-text-05",
"group-active/IconAction:stroke-text-05",
],
disabled: ["stroke-text-01"],
},
internal: {
enabled: [
"stroke-text-02",
"group-hover/IconButton:stroke-text-04",
"group-hover/IconAction:stroke-text-04",
transient && "stroke-text-04",
"group-active/IconButton:stroke-text-05",
"group-active/IconAction:stroke-text-05",
],
disabled: ["stroke-text-01"],
},
small: {
enabled: [
"stroke-text-02",
"group-hover/IconButton:stroke-text-04",
"group-hover/IconAction:stroke-text-04",
transient && "stroke-text-04",
"group-active/IconButton:stroke-text-05",
"group-active/IconAction:stroke-text-05",
],
disabled: ["stroke-text-01"],
},
@@ -202,36 +202,36 @@ const iconClasses = (transient: boolean | undefined) =>
secondary: {
enabled: [
"stroke-action-selection-05",
"group-hover/IconButton:stroke-action-selection-05",
"group-hover/IconAction:stroke-action-selection-05",
transient && "stroke-action-selection-05",
"group-active/IconButton:stroke-action-selection-06",
"group-active/IconAction:stroke-action-selection-06",
],
disabled: ["stroke-action-selection-02"],
},
tertiary: {
enabled: [
"stroke-action-selection-05",
"group-hover/IconButton:stroke-action-selection-05",
"group-hover/IconAction:stroke-action-selection-05",
transient && "stroke-action-selection-05",
"group-active/IconButton:stroke-action-selection-06",
"group-active/IconAction:stroke-action-selection-06",
],
disabled: ["stroke-action-selection-02"],
},
internal: {
enabled: [
"stroke-action-selection-05",
"group-hover/IconButton:stroke-action-selection-05",
"group-hover/IconAction:stroke-action-selection-05",
transient && "stroke-action-selection-05",
"group-active/IconButton:stroke-action-selection-06",
"group-active/IconAction:stroke-action-selection-06",
],
disabled: ["stroke-action-selection-02"],
},
small: {
enabled: [
"stroke-action-selection-05",
"group-hover/IconButton:stroke-action-selection-05",
"group-hover/IconAction:stroke-action-selection-05",
transient && "stroke-action-selection-05",
"group-active/IconButton:stroke-action-selection-06",
"group-active/IconAction:stroke-action-selection-06",
],
disabled: ["stroke-action-selection-02"],
},
@@ -244,36 +244,36 @@ const iconClasses = (transient: boolean | undefined) =>
secondary: {
enabled: [
"stroke-action-danger-05",
"group-hover/IconButton:stroke-action-danger-05",
"group-hover/IconAction:stroke-action-danger-05",
transient && "stroke-action-danger-05",
"group-active/IconButton:stroke-action-danger-06",
"group-active/IconAction:stroke-action-danger-06",
],
disabled: ["stroke-action-danger-02"],
},
tertiary: {
enabled: [
"stroke-action-danger-05",
"group-hover/IconButton:stroke-action-danger-05",
"group-hover/IconAction:stroke-action-danger-05",
transient && "stroke-action-danger-05",
"group-active/IconButton:stroke-action-danger-06",
"group-active/IconAction:stroke-action-danger-06",
],
disabled: ["stroke-action-danger-02"],
},
internal: {
enabled: [
"stroke-action-danger-05",
"group-hover/IconButton:stroke-action-danger-05",
"group-hover/IconAction:stroke-action-danger-05",
transient && "stroke-action-danger-05",
"group-active/IconButton:stroke-action-danger-06",
"group-active/IconAction:stroke-action-danger-06",
],
disabled: ["stroke-action-danger-02"],
},
small: {
enabled: [
"stroke-action-danger-05",
"group-hover/IconButton:stroke-action-danger-05",
"group-hover/IconAction:stroke-action-danger-05",
transient && "stroke-action-danger-05",
"group-active/IconButton:stroke-action-danger-06",
"group-active/IconAction:stroke-action-danger-06",
],
disabled: ["stroke-action-danger-02"],
},
@@ -365,7 +365,7 @@ export default function IconButton({
<button
type="button"
className={cn(
"flex items-center justify-center h-fit w-fit group/IconButton",
"flex items-center justify-center h-fit w-fit group/IconAction",
small || internal ? "p-1" : "p-2",
disabled && "cursor-not-allowed",
small || internal ? "rounded-08" : "rounded-12",
+16 -16
View File
@@ -8,34 +8,34 @@ import type { Route } from "next";
import { Section } from "@/layouts/general-layouts";
import type { WithoutStyles } from "@opal/types";
const buttonClassNames = {
const rowClassNames = {
main: {
normal: "line-item-button-main",
emphasized: "line-item-button-main-emphasized",
normal: "line-item-row-main",
emphasized: "line-item-row-main-emphasized",
},
strikethrough: {
normal: "line-item-button-strikethrough",
emphasized: "line-item-button-strikethrough-emphasized",
normal: "line-item-row-strikethrough",
emphasized: "line-item-row-strikethrough-emphasized",
},
disabled: {
normal: "line-item-button-disabled",
emphasized: "line-item-button-disabled-emphasized",
normal: "line-item-row-disabled",
emphasized: "line-item-row-disabled-emphasized",
},
danger: {
normal: "line-item-button-danger",
emphasized: "line-item-button-danger-emphasized",
normal: "line-item-row-danger",
emphasized: "line-item-row-danger-emphasized",
},
action: {
normal: "line-item-button-action",
emphasized: "line-item-button-action-emphasized",
normal: "line-item-row-action",
emphasized: "line-item-row-action-emphasized",
},
muted: {
normal: "line-item-button-muted",
emphasized: "line-item-button-muted-emphasized",
normal: "line-item-row-muted",
emphasized: "line-item-row-muted-emphasized",
},
skeleton: {
normal: "line-item-button-skeleton",
emphasized: "line-item-button-skeleton-emphasized",
normal: "line-item-row-skeleton",
emphasized: "line-item-row-skeleton-emphasized",
},
} as const;
@@ -230,7 +230,7 @@ export default function LineItem({
"flex flex-row w-full items-start p-2 rounded-08 group/LineItem gap-2",
children && description ? "items-start" : "items-center",
interactive && (disabled ? "cursor-not-allowed" : "cursor-pointer"),
buttonClassNames[variant][emphasisKey]
rowClassNames[variant][emphasisKey]
);
const rowProps = {
@@ -37,9 +37,9 @@ const iconClassNames = (engaged?: boolean, transient?: boolean) =>
main: {
enabled: [
"stroke-text-03",
"group-hover/SelectButton:stroke-text-04",
"group-hover/SelectAction:stroke-text-04",
transient && "stroke-text-04",
"group-active/SelectButton:stroke-text-05",
"group-active/SelectAction:stroke-text-05",
],
disabled: ["stroke-text-02"],
},
@@ -47,11 +47,11 @@ const iconClassNames = (engaged?: boolean, transient?: boolean) =>
enabled: [
engaged ? "stroke-action-selection-05" : "stroke-text-03",
engaged
? "group-hover/SelectButton:stroke-action-selection-05"
: "group-hover/SelectButton:stroke-text-04",
? "group-hover/SelectAction:stroke-action-selection-05"
: "group-hover/SelectAction:stroke-text-04",
engaged
? "group-active/SelectButton:stroke-action-selection-06"
: "group-active/SelectButton:stroke-text-05",
? "group-active/SelectAction:stroke-action-selection-06"
: "group-active/SelectAction:stroke-text-05",
],
disabled: ["stroke-action-selection-03"],
},
@@ -62,9 +62,9 @@ const textClassNames = (engaged?: boolean, transient?: boolean) =>
main: {
enabled: [
"text-text-03",
"group-hover/SelectButton:text-text-04",
"group-hover/SelectAction:text-text-04",
transient && "text-text-04",
"group-active/SelectButton:text-text-05",
"group-active/SelectAction:text-text-05",
],
disabled: ["text-text-01"],
},
@@ -72,11 +72,11 @@ const textClassNames = (engaged?: boolean, transient?: boolean) =>
enabled: [
engaged ? "text-action-selection-05" : "text-text-03",
engaged
? "group-hover/SelectButton:text-action-selection-05"
: "group-hover/SelectButton:text-text-04",
? "group-hover/SelectAction:text-action-selection-05"
: "group-hover/SelectAction:text-text-04",
engaged
? "group-active/SelectButton:text-action-selection-06"
: "group-active/SelectButton:text-text-05",
? "group-active/SelectAction:text-action-selection-06"
: "group-active/SelectAction:text-text-05",
],
disabled: ["stroke-action-selection-03"],
},
@@ -175,7 +175,7 @@ export default function SelectButton({
<button
className={cn(
baseClasses,
"group/SelectButton flex items-center px-2 py-2 rounded-12 h-fit w-fit",
"group/SelectAction flex items-center px-2 py-2 rounded-12 h-fit w-fit",
className
)}
onClick={disabled ? undefined : onClick}