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

fix: fix HTML parsing error #54

Merged
merged 1 commit into from
Jan 26, 2024
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
47 changes: 30 additions & 17 deletions src/MarkdownRenderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,48 @@ import React, { useEffect } from 'react';
import classNames from 'classnames';
import copy from 'copy-to-clipboard';
import mergeRefs from './utils/mergeRefs';
import { iconPath as copyPath } from './icons/Copy';
import { iconPath as copyPath, svgTpl } from './icons/Copy';
import { iconPath as checkPath } from './icons/Check';

interface MarkdownRendererProps extends React.HTMLAttributes<HTMLDivElement> {
children?: string | null;
}

function appendCopyButton(container?: HTMLDivElement | null) {
if (!container) {
return;
}

const button = document.createElement('button');
button.className =
'copy-code-button rs-btn-icon rs-btn-icon-circle rs-btn rs-btn-subtle rs-btn-xs';
button.title = 'Copy code';
button.innerHTML = svgTpl(copyPath);
button.onclick = e => {
e.preventDefault();
const code = container?.querySelector('code')?.textContent;
const icon = button.querySelector('.copy-icon-path');

icon?.setAttribute('d', checkPath);
if (code) {
copy(code);
}

setTimeout(() => {
icon?.setAttribute('d', copyPath);
}, 2000);
};
container?.appendChild(button);
}

const MarkdownRenderer = React.forwardRef(
(props: MarkdownRendererProps, ref: React.Ref<HTMLDivElement>) => {
const { children, className, ...rest } = props;
const mdRef = React.useRef<HTMLDivElement>(null);

useEffect(() => {
mdRef.current?.querySelectorAll('.copy-code-button').forEach(el => {
el.addEventListener('click', e => {
e.preventDefault();

const code = (el.nextElementSibling as HTMLInputElement)?.value;
const icon = el.querySelector('.copy-icon-path');

icon?.setAttribute('d', checkPath);
if (code) {
copy(code);
}

setTimeout(() => {
icon?.setAttribute('d', copyPath);
}, 2000);
});
mdRef.current?.querySelectorAll('.rcv-code-renderer').forEach((el: any) => {
appendCopyButton(el);
});
}, []);

Expand Down
3 changes: 3 additions & 0 deletions src/icons/Copy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ import React from 'react';
export const iconPath =
'M320 448v40c0 13.255-10.745 24-24 24H24c-13.255 0-24-10.745-24-24V120c0-13.255 10.745-24 24-24h72v296c0 30.879 25.121 56 56 56h168zm0-344V0H152c-13.255 0-24 10.745-24 24v368c0 13.255 10.745 24 24 24h272c13.255 0 24-10.745 24-24V128H344c-13.2 0-24-10.8-24-24zm120.971-31.029L375.029 7.029A24 24 0 0 0 358.059 0H352v96h96v-6.059a24 24 0 0 0-7.029-16.97z';

export const svgTpl = (path: string) =>
`<svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 448 512" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg" class="copy-icon"><path class="copy-icon-path" d="${path}"></path></svg>`;

function CopyIcon(props: React.SVGProps<SVGSVGElement>) {
return (
<svg
Expand Down
12 changes: 3 additions & 9 deletions webpack-md-loader/renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,9 @@ module.exports = (languages = defaultLanguages) => {
? hl.highlight(code, { language, ignoreIllegals: true })
: hl.highlightAuto(code);

return `<div class="rcv-highlight">
<button type="button" class="copy-code-button rs-btn-icon rs-btn-icon-circle rs-btn rs-btn-subtle rs-btn-xs" title="Copy code" aria-label="Copy code" >
<svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 448 512" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg">
<path class="copy-icon-path" d="M320 448v40c0 13.255-10.745 24-24 24H24c-13.255 0-24-10.745-24-24V120c0-13.255 10.745-24 24-24h72v296c0 30.879 25.121 56 56 56h168zm0-344V0H152c-13.255 0-24 10.745-24 24v368c0 13.255 10.745 24 24 24h272c13.255 0 24-10.745 24-24V128H344c-13.2 0-24-10.8-24-24zm120.971-31.029L375.029 7.029A24 24 0 0 0 358.059 0H352v96h96v-6.059a24 24 0 0 0-7.029-16.97z"></path>
</svg>
</button>
<input type="hidden" class="copy-code-input" value="${code}" />
<pre><code class="${language || ''}">${value}</code></pre>
</div>`;
return `<div class="rcv-highlight rcv-code-renderer"><pre><code class="${
language || ''
}">${value}</code></pre></div>`;
};

renderer.code = codeRenderer;
Expand Down
Loading