Emulate mkdocs-material copy-to-clipboard functionality.

Signed-off-by: Eric Peterson <ericpeterson@spotify.com>
This commit is contained in:
Eric Peterson
2022-01-20 16:14:59 +01:00
parent bed2da46af
commit a64f99f734
5 changed files with 98 additions and 0 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-techdocs': patch
---
Code snippets now include a "copy to clipboard" button.
@@ -47,6 +47,7 @@ import {
simplifyMkdocsFooter,
scrollIntoAnchor,
transform as transformer,
copyToClipboard,
} from '../transformers';
import { TechDocsSearch } from './TechDocsSearch';
@@ -215,6 +216,8 @@ export const useTechDocsReaderDom = (entityRef: EntityName): Element | null => {
--md-code-fg-color: ${theme.palette.text.primary};
--md-code-bg-color: ${theme.palette.background.paper};
--md-accent-fg-color: ${theme.palette.primary.main};
--md-default-fg-color--lightest: ${theme.palette.textVerySubtle};
}
.md-main__inner { margin-top: 0; }
.md-sidebar { position: fixed; bottom: 100px; width: 20rem; }
@@ -372,6 +375,7 @@ export const useTechDocsReaderDom = (entityRef: EntityName): Element | null => {
async (transformedElement: Element) =>
transformer(transformedElement, [
scrollIntoAnchor(),
copyToClipboard(),
addLinkClickListener({
baseUrl: window.location.origin,
onClick: (event: MouseEvent, url: string) => {
@@ -0,0 +1,49 @@
/*
* Copyright 2020 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { createTestShadowDom } from '../../test-utils';
import { copyToClipboard } from './copyToClipboard';
const clipboardSpy = jest.fn();
Object.defineProperty(navigator, 'clipboard', {
value: {
writeText: clipboardSpy,
},
});
describe('copyToClipboard', () => {
it('calls navigator.clipboard.writeText when clipboard button has been clicked', async () => {
const expectedClipboard = 'function foo() {return "bar";}';
const shadowDom = await createTestShadowDom(
`
<!DOCTYPE html>
<html>
<body>
<code><span>${expectedClipboard}</span></code>
</body>
</html>
`,
{
preTransformers: [],
postTransformers: [copyToClipboard()],
},
);
shadowDom.querySelector('button')?.click();
expect(clipboardSpy).toHaveBeenCalledWith(expectedClipboard);
});
});
@@ -0,0 +1,39 @@
/*
* Copyright 2022 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import type { Transformer } from './transformer';
/**
* Recreates copy-to-clipboard functionality attached to <code> snippets that
* is native to mkdocs-material theme.
*/
export const copyToClipboard = (): Transformer => {
return dom => {
Array.from(dom.querySelectorAll('code')).forEach(codeElem => {
const button = document.createElement('button');
const toBeCopied = codeElem.textContent || '';
button.className = 'md-clipboard md-icon';
button.title = 'Copy to clipboard';
button.innerHTML =
'<svg viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg>';
button.addEventListener('click', () =>
navigator.clipboard.writeText(toBeCopied),
);
codeElem?.parentElement?.prepend(button);
});
return dom;
};
};
@@ -18,6 +18,7 @@ export * from './addBaseUrl';
export * from './addGitFeedbackLink';
export * from './rewriteDocLinks';
export * from './addLinkClickListener';
export * from './copyToClipboard';
export * from './removeMkdocsHeader';
export * from './simplifyMkdocsFooter';
export * from './onCssReady';