{language}
From 3eccee6a5b9a673784554a8f421173aa881d08a9 Mon Sep 17 00:00:00 2001
From: Hrithik Saini <49943287+hrithiksaini99@users.noreply.github.com>
Date: Wed, 4 Nov 2026 11:41:43 +0530
Subject: [PATCH 2/2] fix(ui): address review feedback for ghost copy button
(#9297)
- use DocumentDuplicateIcon and CheckIcon without text for ghost button
- isolate navigator.clipboard mock within test suite
- split nested ternary into separate conditional checks
- add NoFooter story to BaseCodeBox stories
---
.../BaseCodeBox/__tests__/index.test.jsx | 34 ++++++++++++++-----
.../src/Common/BaseCodeBox/index.module.css | 7 ++--
.../src/Common/BaseCodeBox/index.stories.tsx | 10 ++++++
.../src/Common/BaseCodeBox/index.tsx | 24 +++++++++----
4 files changed, 56 insertions(+), 19 deletions(-)
diff --git a/packages/ui-components/src/Common/BaseCodeBox/__tests__/index.test.jsx b/packages/ui-components/src/Common/BaseCodeBox/__tests__/index.test.jsx
index a407039669dd5..52762ae4dff5b 100644
--- a/packages/ui-components/src/Common/BaseCodeBox/__tests__/index.test.jsx
+++ b/packages/ui-components/src/Common/BaseCodeBox/__tests__/index.test.jsx
@@ -1,13 +1,30 @@
-import { describe, it } from 'node:test';
+import { afterEach, beforeEach, describe, it } from 'node:test';
import assert from 'node:assert/strict';
import { render, fireEvent, screen } from '@testing-library/react';
import BaseCodeBox from '../index';
-navigator.clipboard = { writeText: () => Promise.resolve() };
-
describe('BaseCodeBox', () => {
+ let originalClipboard;
+
+ beforeEach(() => {
+ originalClipboard = navigator.clipboard;
+ Object.defineProperty(navigator, 'clipboard', {
+ value: { writeText: () => Promise.resolve() },
+ writable: true,
+ configurable: true,
+ });
+ });
+
+ afterEach(() => {
+ Object.defineProperty(navigator, 'clipboard', {
+ value: originalClipboard,
+ writable: true,
+ configurable: true,
+ });
+ });
+
it('renders code box with language and footer copy button by default', () => {
render(
{
// Language in footer toolbar should NOT be rendered
assert.strictEqual(screen.queryByText('bash'), null);
- // Ghost copy button should be rendered
- const button = screen.getByRole('button');
+ // Ghost copy button should be rendered with accessible label and no visible text
+ const button = screen.getByRole('button', { name: 'Copy code' });
assert.ok(button);
- assert.ok(screen.getByText('Copy code'));
+ assert.strictEqual(screen.queryByText('Copy code'), null);
});
it('copies code content when ghost copy button is clicked', async t => {
@@ -58,10 +75,11 @@ describe('BaseCodeBox', () => {
);
- const button = screen.getByRole('button');
+ const button = screen.getByRole('button', { name: 'Copy code' });
fireEvent.click(button);
- assert.ok(await screen.findByText('Copied!'));
+ const copiedButton = await screen.findByRole('button', { name: 'Copied!' });
+ assert.ok(copiedButton);
assert.strictEqual(navigator.clipboard.writeText.mock.callCount(), 1);
});
});
diff --git a/packages/ui-components/src/Common/BaseCodeBox/index.module.css b/packages/ui-components/src/Common/BaseCodeBox/index.module.css
index 9f43a467778bd..7143555631204 100644
--- a/packages/ui-components/src/Common/BaseCodeBox/index.module.css
+++ b/packages/ui-components/src/Common/BaseCodeBox/index.module.css
@@ -74,7 +74,7 @@
}
&[class*='no-footer'] {
- @apply pr-24;
+ @apply pr-12;
}
}
@@ -83,10 +83,7 @@
top-2
right-2
z-10
- px-2.5
- py-1
- text-xs
- font-medium
+ p-1.5
opacity-0
transition-opacity
duration-150;
diff --git a/packages/ui-components/src/Common/BaseCodeBox/index.stories.tsx b/packages/ui-components/src/Common/BaseCodeBox/index.stories.tsx
index 6cc32c8b24169..bdbff01b6908a 100644
--- a/packages/ui-components/src/Common/BaseCodeBox/index.stories.tsx
+++ b/packages/ui-components/src/Common/BaseCodeBox/index.stories.tsx
@@ -27,4 +27,14 @@ export const Default: Story = {
},
};
+export const NoFooter: Story = {
+ args: {
+ language: 'bash',
+ className: 'no-footer',
+ copyButtonLabel: 'Copy code',
+ copiedButtonLabel: 'Copied!',
+ children:
node --no-deprecation app.js,
+ },
+};
+
export default { component: BaseCodeBox } as Meta;
diff --git a/packages/ui-components/src/Common/BaseCodeBox/index.tsx b/packages/ui-components/src/Common/BaseCodeBox/index.tsx
index 231043e4cc075..b966a48143640 100644
--- a/packages/ui-components/src/Common/BaseCodeBox/index.tsx
+++ b/packages/ui-components/src/Common/BaseCodeBox/index.tsx
@@ -3,6 +3,7 @@
import {
DocumentDuplicateIcon,
CodeBracketIcon,
+ CheckIcon,
} from '@heroicons/react/24/outline';
import classNames from 'classnames';
import { Fragment, isValidElement, useRef } from 'react';
@@ -88,10 +89,13 @@ const BaseCodeBox: FC
> = ({
const handleCopy = () => copy(containerRef.current?.textContent);
- const ButtonIcon = copied ? DocumentDuplicateIcon : CodeBracketIcon;
+ const FooterButtonIcon = copied ? DocumentDuplicateIcon : CodeBracketIcon;
const hideFooter = className?.includes('no-footer');
+ const activeLabel = copied ? copiedButtonLabel : copyButtonLabel;
+ const ghostLabel = typeof activeLabel === 'string' ? activeLabel : undefined;
+
return (
> = ({
{transformCode(children as ReactElement, language)}
- {hideFooter ? (
+ {hideFooter && (
-
- {copied ? copiedButtonLabel : copyButtonLabel}
+ {copied ? (
+
+ ) : (
+
+ )}
- ) : !language ? null : (
+ )}
+
+ {!hideFooter && Boolean(language) && (
{language}
@@ -122,7 +134,7 @@ const BaseCodeBox: FC
> = ({
kind="neutral"
onClick={handleCopy}
>
-
+
{copied ? copiedButtonLabel : copyButtonLabel}