diff --git a/src/components/Icons/IconClipboard.tsx b/src/components/Icons/IconClipboard.tsx
new file mode 100644
index 00000000000..a08a8ef7faf
--- /dev/null
+++ b/src/components/Icons/IconClipboard.tsx
@@ -0,0 +1,21 @@
+import { Icon } from '@aws-amplify/ui-react';
+
+export const IconClipboard = ({ ...rest }) => {
+ return (
+
+
+
+ );
+};
diff --git a/src/components/Icons/index.ts b/src/components/Icons/index.ts
index a492f2c55c0..d28d62f5d8b 100644
--- a/src/components/Icons/index.ts
+++ b/src/components/Icons/index.ts
@@ -5,6 +5,7 @@ export { IconAWS } from './IconAWS';
export { IconCheck } from './IconCheck';
export { IconCheckCircle } from './IconCheckCircle';
export { IconChevron } from './IconChevron';
+export { IconClipboard } from './IconClipboard';
export { IconDark } from './IconDark';
export { IconDiscord } from './IconDiscord';
export { IconDoubleChevron } from './IconDoubleChevron';
diff --git a/src/components/MDXComponents/MDXCopyCodeButton.tsx b/src/components/MDXComponents/MDXCopyCodeButton.tsx
index 6c1e2429832..ad76cf72a58 100644
--- a/src/components/MDXComponents/MDXCopyCodeButton.tsx
+++ b/src/components/MDXComponents/MDXCopyCodeButton.tsx
@@ -3,7 +3,7 @@ import { CopyToClipboard } from 'react-copy-to-clipboard';
import { Button, VisuallyHidden } from '@aws-amplify/ui-react';
import { trackCopyClicks } from '@/utils/track';
import { prepareCopyText } from './utils/copy-code';
-
+import { IconClipboard } from '@/components/Icons';
interface MDXCopyCodeButtonProps {
codeId: string;
codeString: string;
@@ -38,7 +38,7 @@ export const MDXCopyCodeButton = ({
testId={testId}
aria-describedby={title ? undefined : codeId}
>
- {copied ? 'Copied!' : 'Copy'}
+ {copied ? 'Copied!' : 'Copy'}
{` `}
{title} code example
diff --git a/src/components/MDXComponents/MDXHighlightedCode.tsx b/src/components/MDXComponents/MDXHighlightedCode.tsx
new file mode 100644
index 00000000000..7de2c4217be
--- /dev/null
+++ b/src/components/MDXComponents/MDXHighlightedCode.tsx
@@ -0,0 +1,53 @@
+import { useState, useId } from 'react';
+import { CopyToClipboard } from 'react-copy-to-clipboard';
+import { Button, VisuallyHidden } from '@aws-amplify/ui-react';
+import { trackCopyClicks } from '@/utils/track';
+import { prepareCopyText } from './utils/copy-code';
+import { IconClipboard } from '@/components/Icons';
+interface MDXHighlightedCodeProps {
+ codeString: string;
+ testId?: string;
+ children?: React.ReactNode;
+}
+
+export const MDXHighlightedCode = ({
+ codeString,
+ children
+}: MDXHighlightedCodeProps) => {
+ const [copied, setCopied] = useState(false);
+
+ const copyText = prepareCopyText(codeString);
+ const highlightCodeId = useId();
+
+ const copy = () => {
+ trackCopyClicks(copyText);
+ setCopied(true);
+ setTimeout(() => {
+ setCopied(false);
+ }, 2000);
+ };
+ return (
+ <>
+
+
+
+
+
+ {children}
+
+
+ >
+ );
+};
diff --git a/src/components/MDXComponents/MDXHighlightedCopyCodeButton.tsx b/src/components/MDXComponents/MDXHighlightedCopyCodeButton.tsx
deleted file mode 100644
index 7fdf4604f99..00000000000
--- a/src/components/MDXComponents/MDXHighlightedCopyCodeButton.tsx
+++ /dev/null
@@ -1,46 +0,0 @@
-import { useState } from 'react';
-import { CopyToClipboard } from 'react-copy-to-clipboard';
-import { VisuallyHidden } from '@aws-amplify/ui-react';
-import { trackCopyClicks } from '@/utils/track';
-import { prepareCopyText } from './utils/copy-code';
-
-interface MDXCopyCodeButtonProps {
- codeId: string;
- codeString: string;
- testId?: string;
- title?: string;
- children?: React.ReactNode;
-}
-
-export const MDXHighlightedCopyCodeButton = ({
- codeString,
- title,
- codeId,
- children
-}: MDXCopyCodeButtonProps) => {
- const [copied, setCopied] = useState(false);
-
- const copyText = prepareCopyText(codeString);
-
- const copy = () => {
- trackCopyClicks(copyText);
- setCopied(true);
- setTimeout(() => {
- setCopied(false);
- }, 2000);
- };
- return (
-
-
-
- );
-};
diff --git a/src/components/MDXComponents/TokenList.tsx b/src/components/MDXComponents/TokenList.tsx
index 9078453bc20..9b3962ff1e5 100644
--- a/src/components/MDXComponents/TokenList.tsx
+++ b/src/components/MDXComponents/TokenList.tsx
@@ -1,6 +1,6 @@
import type { Token } from 'prism-react-renderer';
import type { TokenListProps } from './types';
-import { MDXHighlightedCopyCodeButton } from './MDXHighlightedCopyCodeButton';
+import { MDXHighlightedCode } from './MDXHighlightedCode';
import classNames from 'classnames';
type ProcessedToken = {
@@ -159,8 +159,7 @@ export const TokenList = ({
.join('\n');
return (
-
@@ -172,7 +171,7 @@ export const TokenList = ({
showLineNumbers
);
})}
-
+
);
}
});
diff --git a/src/styles/code.scss b/src/styles/code.scss
index 53d05364613..b5699390d3e 100644
--- a/src/styles/code.scss
+++ b/src/styles/code.scss
@@ -37,7 +37,7 @@ code:not([class]) {
}
.pre-wrapper {
- padding: 0 var(--amplify-space-large) 0 var(--amplify-space-xs);
+ padding: 0 var(--amplify-space-xs);
}
.pre-header {
@@ -70,13 +70,16 @@ code:not([class]) {
-webkit-text-size-adjust: 100%;
&:focus-visible {
- outline: none;
- box-shadow: 0 0 0 2px var(--amplify-colors-white) inset;
+ outline: 2px solid #fff;
+ outline-offset: 2px;
}
}
.pre-code {
flex: 1;
+ display: flex;
+ flex-direction: column;
+ --highlight-code-hover-background-color: hsl(211, 22%, 19%);
}
.token-line {
@@ -92,7 +95,15 @@ code:not([class]) {
}
.line-highlight {
+ &:first-child {
+ padding-top: var(--amplify-space-xxs);
+ }
+ &:last-child {
+ padding-bottom: var(--amplify-space-xxs);
+ }
&:before {
+ transition: background-color
+ var(--amplify-components-button-transition-duration) ease;
content: '';
position: absolute;
left: 0;
@@ -138,45 +149,101 @@ code:not([class]) {
width: 1.8rem;
}
-.highlight-copy-block {
- all: unset;
- width: 100%;
- cursor: pointer;
+.highlight-copy-button {
+ background-color: var(--amplify-colors-neutral-90);
+ margin-top: var(--amplify-space-xxs);
+ border-color: transparent;
+ color: #fff;
+ align-self: flex-start;
+ border-end-end-radius: 0;
+ border-end-start-radius: 0;
+ margin-inline-start: var(--amplify-space-xxl);
position: relative;
-}
-
-.highlight-copy-block-hint {
- position: absolute;
- top: 0;
- right: 1.8rem;
- color: white;
-}
-
-.highlight-copy-block .highlight-c4py-block-hint {
- display: none;
-}
-
-.highlight-copy-block:focus .highlight-copy-block-hint {
- display: block;
-}
-
-.highlight-copy-block:hover .highlight-copy-block-hint {
- display: block;
-}
-
-.highlight-copy-block:focus .line-highlight::before {
- background-color: var(--amplify-colors-primary-80);
-
+ user-select: none;
+ gap: var(--amplify-space-xxs);
+ &:focus {
+ box-shadow: none;
+ }
+ &:focus-visible {
+ outline: 2px solid #fff;
+ outline-offset: -2px;
+ &:after {
+ content: '';
+ position: absolute;
+ height: 2px;
+ left: 1px;
+ right: 1px;
+ bottom: -1px;
+ background-color: var(--amplify-colors-neutral-90);
+ z-index: 2;
+ }
+ & + .highlight-code {
+ outline: 2px solid #fff;
+ .line-highlight:after {
+ background-color: #fff;
+ }
+ }
+ }
+ &:hover {
+ background-color: var(--highlight-code-hover-background-color);
+ &:after {
+ background-color: var(--highlight-code-hover-background-color);
+ }
+ & + .highlight-code {
+ .line-highlight:before {
+ background-color: var(--highlight-code-hover-background-color);
+ }
+ }
+ }
@include darkMode {
- background-color: var(--amplify-colors-neutral-40);
+ background-color: var(--amplify-colors-neutral-20);
+ &:focus-visible {
+ &:after {
+ background-color: var(--amplify-colors-neutral-20);
+ }
+ }
+ &:hover {
+ background-color: var(--highlight-code-hover-background-color);
+ &:after {
+ background-color: var(--highlight-code-hover-background-color);
+ }
+ & + .highlight-code {
+ .line-highlight:before {
+ background-color: var(--highlight-code-hover-background-color);
+ }
+ }
+ }
}
}
-.highlight-copy-block:hover .line-highlight::before {
- background-color: var(--amplify-colors-primary-90);
+/* This :has selector allows us to style the .highlight-copy-button
+that is preceding the .highlight-code block so that interaction between
+them looks "connected", i.e. the hover style on one triggers the
+hover style on the other */
+.highlight-copy-button:has(+ .highlight-code:hover) {
+ background-color: var(--highlight-code-hover-background-color);
+ &:focus-visible {
+ &:after {
+ height: 4px;
+ bottom: -3px;
+ background-color: var(--highlight-code-hover-background-color);
+ }
+ }
+ &:hover {
+ &:after {
+ background-color: var(--highlight-code-hover-background-color);
+ }
+ }
+}
- @include darkMode {
- background-color: var(--amplify-colors-primary-10);
+.highlight-code {
+ position: relative;
+ margin-bottom: var(--amplify-space-xxs);
+ &:hover {
+ cursor: pointer;
+ .line-highlight:before {
+ background-color: var(--highlight-code-hover-background-color);
+ }
}
}
@@ -188,6 +255,7 @@ code:not([class]) {
padding-block: var(--amplify-space-xxxs);
color: var(--amplify-colors-white);
border-radius: var(--amplify-radii-small);
+ gap: var(--amplify-space-xxs);
&:hover {
color: var(--amplify-colors-white);
background-color: var(--code-copy-hover-background-color);
@@ -202,4 +270,4 @@ code:not([class]) {
--code-copy-focus-background-color: var(--amplify-colors-neutral-20);
--code-copy-focus-box-shadow: var(--amplify-colors-neutral-100);
}
-}
\ No newline at end of file
+}