Skip to content

Commit

Permalink
feat(code_block): allow for a custom copy button aria-label
Browse files Browse the repository at this point in the history
closes #8004
  • Loading branch information
weronikaolejniczak committed Nov 22, 2024
1 parent df7a98f commit 5c7e110
Show file tree
Hide file tree
Showing 8 changed files with 126 additions and 2 deletions.
3 changes: 3 additions & 0 deletions packages/eui/changelogs/upcoming/8176.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
**Accessibility**

- Allowed to pass a custom `aria-label` for the Copy button in the EuiCodeBlock component.
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import React from 'react';

import { EuiCodeBlock } from '../../../../src/components';

const htmlCode = `<!-- I'm an example of HTML -->
<h1>Hello world!</h1>
<p>Lorem ipsum dolor sit amet.</p>`;

export default () => (
<EuiCodeBlock language="html" isCopyable customCopyAriaLabel="Copy this code">
{htmlCode}
</EuiCodeBlock>
);
19 changes: 19 additions & 0 deletions packages/eui/src-docs/src/views/code/code_example.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ const codeBlockCopySnippet = `<EuiCodeBlock language="html" isCopyable>
</EuiCodeBlock>
`;

import CodeBlockCustomCopyAriaLabel from './code_block_custom_copy_aria_label';
const codeBlockCustomCopyAriaLabelSnippet = `<EuiCodeBlock language="html" isCopyable customCopyAriaLabel="Copy this code">
{...}
</EuiCodeBlock>
`;

import CodeBlockOverflow from './code_block_overflow';
const codeBlockOverflowSource = require('!!raw-loader!./code_block_overflow');
const codeBlockOverflowSnippet = `<EuiCodeBlock language="html" overflowHeight={300}>
Expand Down Expand Up @@ -177,6 +183,19 @@ export const CodeExample = {
props: { EuiCodeBlock },
demo: <CodeBlockCopy />,
},
{
text: (
<p>
You can specify a custom aria label for the Copy button using the
<EuiCode>customCopyAriaLabel</EuiCode> prop. It works in conjunction
with the
<EuiCode>isCopyable</EuiCode> prop.
</p>
),
snippet: codeBlockCustomCopyAriaLabelSnippet,
props: { EuiCodeBlock },
demo: <CodeBlockCustomCopyAriaLabel />,
},
{
text: (
<p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,59 @@ exports[`EuiCodeBlock line numbers renders line numbers with a start value 1`] =
</div>
`;

exports[`EuiCodeBlock props customCopyAriaLabel is rendered 1`] = `
<div
class="euiCodeBlock emotion-euiCodeBlock-s-hasControls"
>
<pre
class="euiCodeBlock__pre emotion-euiCodeBlock__pre-preWrap-padding-controlsOffset"
tabindex="-1"
>
<code
class="euiCodeBlock__code emotion-euiCodeBlock__code"
data-code-language="text"
>
<span
class="euiCodeBlock__line emotion-euiCodeBlock__line"
>
var some = 'code';
</span>
<span
class="euiCodeBlock__line emotion-euiCodeBlock__line"
>
console.log(some);
</span>
</code>
</pre>
<div
class="euiCodeBlock__controls emotion-euiCodeBlock__controls-l"
>
<div
class="euiCodeBlock__copyButton"
>
<span
class="euiToolTipAnchor emotion-euiToolTipAnchor-inlineBlock"
>
<button
aria-label="Copy this code"
class="euiButtonIcon emotion-euiButtonIcon-xs-empty-text"
data-test-subj="euiCodeBlockCopy"
type="button"
>
<span
aria-hidden="true"
class="euiButtonIcon__icon"
color="inherit"
data-euiicon-type="copyClipboard"
/>
</button>
</span>
</div>
</div>
</div>
`;

exports[`EuiCodeBlock props fontSize l is rendered 1`] = `
<div
class="euiCodeBlock emotion-euiCodeBlock-l"
Expand Down
13 changes: 13 additions & 0 deletions packages/eui/src/components/code/code_block.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,19 @@ describe('EuiCodeBlock', () => {
});
});

describe('customCopyAriaLabel', () => {
it('is rendered', () => {
const customLabel = 'Copy this code';
const { container } = render(
<EuiCodeBlock isCopyable customCopyAriaLabel={customLabel}>
{code}
</EuiCodeBlock>
);

expect(container.firstChild).toMatchSnapshot();
});
});

describe('overflowHeight', () => {
it('is rendered', () => {
const { container } = render(
Expand Down
7 changes: 7 additions & 0 deletions packages/eui/src/components/code/code_block.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,11 @@ export type EuiCodeBlockProps = EuiCodeSharedProps & {
*/
isCopyable?: boolean;

/**
* Customizes the aria-label for the copy button.
*/
customCopyAriaLabel?: string;

/**
* Displays line numbers.
* Optionally accepts a configuration object for setting the starting number,
Expand Down Expand Up @@ -118,6 +123,7 @@ export const EuiCodeBlock: FunctionComponent<EuiCodeBlockProps> = ({
paddingSize = 'l',
fontSize = 's',
isCopyable = false,
customCopyAriaLabel,
whiteSpace = 'pre-wrap',
children,
className,
Expand Down Expand Up @@ -159,6 +165,7 @@ export const EuiCodeBlock: FunctionComponent<EuiCodeBlockProps> = ({
);

const { innerTextRef, copyButton } = useCopy({
customCopyAriaLabel,
isCopyable,
isVirtualized,
children,
Expand Down
6 changes: 4 additions & 2 deletions packages/eui/src/components/code/code_block_copy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@ import { NEW_LINE_REGEX_GLOBAL } from './utils';
* Hook that returns copy-related state/logic/utils
*/
export const useCopy = ({
customCopyAriaLabel,
isCopyable,
isVirtualized,
children,
}: {
customCopyAriaLabel?: string;
isCopyable: boolean;
isVirtualized: boolean;
children: ReactNode;
Expand Down Expand Up @@ -52,14 +54,14 @@ export const useCopy = ({
onClick={copy}
iconType="copyClipboard"
color="text"
aria-label={copyAriaLabel}
aria-label={customCopyAriaLabel || copyAriaLabel}
data-test-subj="euiCodeBlockCopy"
/>
)}
</EuiCopy>
</div>
) : null;
}, [showCopyButton, textToCopy, copyAriaLabel]);
}, [copyAriaLabel, customCopyAriaLabel, showCopyButton, textToCopy]);

return { innerTextRef, copyButton };
};
14 changes: 14 additions & 0 deletions packages/website/docs/components/editors_and_syntax/code.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,20 @@ export default () => (

```

You can specify a custom aria label for the Copy button using the `customCopyAriaLabel` prop. It works in conjunction with the `isCopyable` prop.

```tsx
import React from 'react';
import { EuiCodeBlock } from '@elastic/eui';

export default () => (
<EuiCodeBlock language="html" isCopyable customCopyAriaLabel="Copy the code">
{...}
</EuiCodeBlock>
);

```

For long content, you can set an `overflowHeight` which will scroll if the text exceeds that height, and allows users to view the code in fullscreen mode.

```tsx interactive
Expand Down

0 comments on commit 5c7e110

Please sign in to comment.