Emulate mkdocs-material copy-to-clipboard functionality.
Signed-off-by: Eric Peterson <ericpeterson@spotify.com>
This commit is contained in:
@@ -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';
|
||||
|
||||
Reference in New Issue
Block a user