Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(CodeBlocks): add lines highlight support #784

Merged
merged 1 commit into from
May 3, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 30 additions & 7 deletions components/CodeBlocks/BlockCode.module.css
Original file line number Diff line number Diff line change
@@ -1,11 +1,34 @@
.code {
@apply static !important;
@apply mb-0 p-5 !important;
@apply static;
@apply mb-0 px-0 py-5;
}

.line {
@apply inline-block !important;
@apply w-6 !important;
@apply mr-3 !important;
@apply text-secondary select-none !important;
.code div {
@apply relative;
}

.hover,
.highlight {
@apply absolute;
@apply w-full h-full;
}

.hover:hover,
.highlight {
@apply bg-gray-100/10;
}

.highlight {
@apply border-l-4 border-solid border-l-primary;
}

.number {
@apply inline-block;
@apply w-6;
@apply ml-5 mr-3;
@apply text-secondary select-none;
}

.placeholder {
@apply ml-5;
}
20 changes: 1 addition & 19 deletions components/CodeBlocks/BlockCode.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,29 +27,11 @@ describe('BlockCode', () => {
'rust',
];

test('should hidden line number and copy button according code block metadata (snapshot)', () => {
const { container } = render(
<BlockCode
enableLine={false}
enableCopy={false}
className="language-type"
>
const foo = bar();
</BlockCode>
);

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

test.each(languages)(
'should render different language correctly (snapshot)',
language => {
const { container } = render(
<BlockCode
enableLine={true}
enableCopy={true}
className={`language-${language}`}
>
<BlockCode className={`language-${language}`}>
const foo = bar();
</BlockCode>
);
Expand Down
63 changes: 34 additions & 29 deletions components/CodeBlocks/BlockCode.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import CopyButton from '@components/CopyButton';
import { classNames } from '@components/utils';
import type { Language } from 'prism-react-renderer';
import Highlight, { defaultProps } from 'prism-react-renderer';
Expand All @@ -7,40 +6,46 @@ import theme from './monokai';
import { normalizeCode } from './utils';

interface Props {
enableLine: boolean;
enableCopy: boolean;
enableLine?: boolean;
lines?: Set<number>;
children?: string;
className?: string;
}

const BlockCode = ({
enableLine,
enableCopy,
enableLine = true,
lines = new Set(),
children,
className,
}: Props): JSX.Element => (
<Highlight
{...defaultProps}
theme={theme}
code={normalizeCode(children)}
language={className?.replace('language-', '') as Language}
>
{({ className, style, tokens, getLineProps, getTokenProps }) => (
<pre className={classNames(className, styles.code)} style={style}>
{enableCopy ? <CopyButton code={normalizeCode(children)} /> : null}
{tokens.map((line, index) => (
<div key={index} {...getLineProps({ line, key: index })}>
{enableLine ? (
<span className={styles.line}>{index + 1}</span>
) : null}
{line.map((token, key) => (
<span key={key} {...getTokenProps({ token, key })} />
))}
</div>
))}
</pre>
)}
</Highlight>
);
}: Props): JSX.Element => {
const code = normalizeCode(children);
const language = className?.replace('language-', '') as Language;

return (
<Highlight {...defaultProps} theme={theme} code={code} language={language}>
{({ className, style, tokens, getLineProps, getTokenProps }) => (
<pre className={classNames(className, styles.code)} style={style}>
{tokens.map((line, index) => (
<div key={index} {...getLineProps({ line, key: index })}>
{lines.has(index + 1) ? (
<span className={styles.highlight}></span>
) : (
<span className={styles.hover}></span>
)}
{enableLine ? (
<span className={styles.number}>{index + 1}</span>
) : (
<span className={styles.placeholder}></span>
)}
{line.map((token, key) => (
<span key={key} {...getTokenProps({ token, key })} />
))}
</div>
))}
</pre>
)}
</Highlight>
);
};

export default BlockCode;
40 changes: 40 additions & 0 deletions components/CodeBlocks/Pre.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,46 @@ describe('Pre', () => {
expect(container).toMatchSnapshot();
});

test('should hidden line number correctly (snapshot)', () => {
const { container } = render(
<Pre noline={true}>
<code>Code</code>
</Pre>
);

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

test('should hidden copy button correctly (snapshot)', () => {
const { container } = render(
<Pre nocopy={true}>
<code>Code</code>
</Pre>
);

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

test('should render code title correctly (snapshot)', () => {
const { container } = render(
<Pre title="Code Title">
<code>Code</code>
</Pre>
);

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

test('should render highlight lines correctly (snapshot)', () => {
const { container } = render(
<Pre lines="1">
<code>Code</code>
</Pre>
);

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

test('should render live code correctly (snapshot)', () => {
const { container } = render(
<Pre live={true}>
Expand Down
11 changes: 8 additions & 3 deletions components/CodeBlocks/Pre.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,25 @@
import CopyButton from '@components/CopyButton';
import { classNames } from '@components/utils';
import type { HTMLProps, ReactElement } from 'react';
import BlockCode from './BlockCode';
import LiveCode from './LiveCode';
import styles from './Pre.module.css';
import { normalizeLanguage } from './utils';
import { normalizeLanguage, normalizeLines } from './utils';

interface Props extends HTMLProps<HTMLPreElement> {
live?: boolean;
noline?: boolean;
nocopy?: boolean;
title?: string;
lines?: string;
}

const Pre = ({
live = false,
noline = false,
nocopy = false,
title,
title = '',
lines = '',
children,
className,
}: Props): JSX.Element => {
Expand All @@ -26,18 +29,20 @@ const Pre = ({
const languageName = normalizeLanguage(
languageClass?.replace('language-', '')
);
const highlightLines = normalizeLines(lines);

return (
<pre
className={classNames(className, languageClass, styles.pre)}
data-language={title || languageName}
>
{!nocopy ? <CopyButton code={code} /> : null}
{live ? (
<LiveCode className={languageClass}>{code}</LiveCode>
) : (
<BlockCode
enableLine={!noline}
enableCopy={!nocopy}
lines={highlightLines}
className={languageClass}
>
{code}
Expand Down
Loading