|
@@ -1,18 +1,6 @@
|
|
|
-// eslint-disable-next-line simple-import-sort/imports
|
|
|
-import 'prismjs/themes/prism.css';
|
|
|
-
|
|
|
-import {useEffect, useRef, useState} from 'react';
|
|
|
-import {useTheme, Theme} from '@emotion/react';
|
|
|
import styled from '@emotion/styled';
|
|
|
-import copy from 'copy-text-to-clipboard';
|
|
|
-import Prism from 'prismjs';
|
|
|
-/**
|
|
|
- * JSX syntax for Prism. This file uses Prism
|
|
|
- * internally, so it must be imported after Prism.
|
|
|
- */
|
|
|
-import 'prismjs/components/prism-jsx.min';
|
|
|
|
|
|
-import {IconCode} from 'sentry/icons';
|
|
|
+import {CodeSnippet} from 'sentry/components/codeSnippet';
|
|
|
import space from 'sentry/styles/space';
|
|
|
|
|
|
type Props = {
|
|
@@ -36,81 +24,29 @@ type Props = {
|
|
|
* the label prop is set to 'hello'
|
|
|
*/
|
|
|
label?: string;
|
|
|
- theme?: Theme;
|
|
|
};
|
|
|
|
|
|
const Code = ({children, className, label}: Props) => {
|
|
|
- const theme = useTheme();
|
|
|
- const codeRef = useRef<HTMLElement | null>(null);
|
|
|
- const copyTimeoutRef = useRef<number | undefined>(undefined);
|
|
|
-
|
|
|
- const [copied, setCopied] = useState(false);
|
|
|
-
|
|
|
- function handleCopyCode() {
|
|
|
- // Remove comments from code
|
|
|
- const copiableContent = children.replace(/\/\*[\s\S]*?\*\/|\/\/.*/g, '');
|
|
|
-
|
|
|
- copy(copiableContent);
|
|
|
- setCopied(true);
|
|
|
-
|
|
|
- copyTimeoutRef.current = window.setTimeout(() => {
|
|
|
- setCopied(false);
|
|
|
- }, 500);
|
|
|
- }
|
|
|
-
|
|
|
- // Cleanup timeout on component unmount
|
|
|
- useEffect(() => {
|
|
|
- return () => {
|
|
|
- if (copyTimeoutRef.current !== null) {
|
|
|
- window.clearTimeout(copyTimeoutRef.current);
|
|
|
- }
|
|
|
- };
|
|
|
- }, []);
|
|
|
-
|
|
|
- useEffect(() => {
|
|
|
- Prism.highlightElement(codeRef.current, false);
|
|
|
- }, [children]);
|
|
|
-
|
|
|
return (
|
|
|
- <Wrap className={className}>
|
|
|
- <LabelWrap>
|
|
|
- <IconCode theme={theme} color="subText" />
|
|
|
- {label && <Label>{label.replaceAll('_', ' ')}</Label>}
|
|
|
- </LabelWrap>
|
|
|
- <HighlightedCode className={className} ref={codeRef}>
|
|
|
+ <CodeWrap className={className}>
|
|
|
+ <LabelWrap>{label && <Label>{label.replaceAll('_', ' ')}</Label>}</LabelWrap>
|
|
|
+ <CodeSnippet language={className?.split('language-')[1] ?? ''}>
|
|
|
{children}
|
|
|
- </HighlightedCode>
|
|
|
- <CopyButton onClick={handleCopyCode} disabled={copied}>
|
|
|
- {copied ? 'Copied' : 'Copy'}
|
|
|
- </CopyButton>
|
|
|
- </Wrap>
|
|
|
+ </CodeSnippet>
|
|
|
+ </CodeWrap>
|
|
|
);
|
|
|
};
|
|
|
|
|
|
export default Code;
|
|
|
|
|
|
-const Wrap = styled('pre')`
|
|
|
- /* Increase specificity to override default styles */
|
|
|
- && {
|
|
|
- position: relative;
|
|
|
- padding: ${space(2)};
|
|
|
- padding-top: ${space(4)};
|
|
|
- margin-top: ${space(4)};
|
|
|
- margin-bottom: ${space(2)};
|
|
|
- background: ${p => p.theme.bodyBackground};
|
|
|
- border: solid 1px ${p => p.theme.border};
|
|
|
- overflow: visible;
|
|
|
- text-shadow: none;
|
|
|
- }
|
|
|
- & code {
|
|
|
- text-shadow: none;
|
|
|
- }
|
|
|
+const CodeWrap = styled('div')`
|
|
|
+ position: relative;
|
|
|
+ padding: ${space(2)} 0;
|
|
|
|
|
|
- /* Overwrite default Prism behavior to allow for code wrapping */
|
|
|
- pre[class*='language-'],
|
|
|
- code[class*='language-'] {
|
|
|
- white-space: normal;
|
|
|
- word-break: break-word;
|
|
|
+ pre {
|
|
|
+ font-size: ${p => p.theme.fontSizeMedium};
|
|
|
+ border: solid 1px ${p => p.theme.border};
|
|
|
+ padding-top: ${space(2)};
|
|
|
}
|
|
|
`;
|
|
|
|
|
@@ -118,47 +54,22 @@ const LabelWrap = styled('div')`
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
position: absolute;
|
|
|
- top: 0;
|
|
|
+ top: ${space(2)};
|
|
|
left: calc(${space(2)} - ${space(1)});
|
|
|
transform: translateY(-50%);
|
|
|
- padding: ${space(0.25)} ${space(1)};
|
|
|
+ z-index: 1;
|
|
|
+
|
|
|
+ padding: 0 ${space(0.75)};
|
|
|
background: ${p => p.theme.docsBackground};
|
|
|
- border: solid 1px ${p => p.theme.border};
|
|
|
+ border: solid 1px ${p => p.theme.innerBorder};
|
|
|
border-radius: ${p => p.theme.borderRadius};
|
|
|
`;
|
|
|
|
|
|
const Label = styled('p')`
|
|
|
- font-size: 0.875rem;
|
|
|
- font-weight: 600;
|
|
|
color: ${p => p.theme.subText};
|
|
|
- text-transform: uppercase;
|
|
|
- margin-bottom: 0;
|
|
|
- margin-left: ${space(1)};
|
|
|
-`;
|
|
|
-
|
|
|
-const HighlightedCode = styled('code')`
|
|
|
- /** Increase specificity to override default styles */
|
|
|
- ${Wrap} > & {
|
|
|
- font-family: ${p => p.theme.text.familyMono};
|
|
|
- font-size: 0.875rem;
|
|
|
- line-height: 1.6;
|
|
|
- }
|
|
|
-`;
|
|
|
-
|
|
|
-const CopyButton = styled('button')`
|
|
|
- position: absolute;
|
|
|
- top: ${space(0.5)};
|
|
|
- right: ${space(0.5)};
|
|
|
- background: transparent;
|
|
|
- border: none;
|
|
|
- border-radius: ${p => p.theme.borderRadius};
|
|
|
- padding: ${space(0.5)} ${space(1)};
|
|
|
-
|
|
|
- font-size: 0.875rem;
|
|
|
+ font-size: ${p => p.theme.fontSizeMedium};
|
|
|
font-weight: 600;
|
|
|
- color: ${p => p.theme.subText};
|
|
|
|
|
|
- &:hover:not(:disabled) {
|
|
|
- color: ${p => p.theme.textColor};
|
|
|
- }
|
|
|
+ text-transform: uppercase;
|
|
|
+ margin-bottom: 0;
|
|
|
`;
|