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

Render markdown preview cells inside a shadow dom #120137

Merged
merged 2 commits into from Mar 30, 2021
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 5 additions & 0 deletions extensions/markdown-language-features/notebook/index.ts
Expand Up @@ -24,5 +24,10 @@ type extendMarkdownItFnType = (
notebook.onDidCreateMarkdown(({ element, content }: any) => {
const rendered = markdownIt.render(content);
element.innerHTML = rendered;

// Insert styles into markdown preview shadow dom so that they are applied
for (const markdownStyleNode of document.getElementsByClassName('markdown-style')) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the future, we should look into pulling in contributed styles through some explicit contribution point instead of this implicit convention

element.appendChild(markdownStyleNode.cloneNode(true));
}
});
}());
12 changes: 12 additions & 0 deletions extensions/markdown-language-features/notebook/tsconfig.json
@@ -0,0 +1,12 @@
{
"extends": "../../shared.tsconfig.json",
"compilerOptions": {
"outDir": "./dist/",
"jsx": "react",
"lib": [
"es2018",
"DOM",
"DOM.Iterable"
]
}
}
1 change: 1 addition & 0 deletions extensions/notebook-markdown-extensions/notebook/katex.ts
Expand Up @@ -12,6 +12,7 @@ const styleHref = (document.currentScript as any).src.replace(/katex.js$/, 'kate

const link = document.createElement('link');
link.rel = 'stylesheet';
link.classList.add('markdown-style');
link.href = styleHref;

document.head.append(link);
Expand Down
Expand Up @@ -407,6 +407,152 @@ export class BackLayerWebView<T extends ICommonCellInfo> extends Disposable {
<head>
<meta charset="UTF-8">
<base href="${baseUrl}/"/>

<!--
Markdown previews are rendered using a shadow dom and are not effected by normal css.
Insert this style node into all preview shadow doms for styling.
-->
<template id="preview-styles">
<style>
img {
max-width: 100%;
max-height: 100%;
}

a {
text-decoration: none;
}

a:hover {
text-decoration: underline;
}

a:focus,
input:focus,
select:focus,
textarea:focus {
outline: 1px solid -webkit-focus-ring-color;
outline-offset: -1px;
}

hr {
border: 0;
height: 2px;
border-bottom: 2px solid;
}

h1 {
font-size: 26px;
padding-bottom: 8px;
line-height: 31px;
border-bottom-width: 1px;
border-bottom-style: solid;
border-color: var(--vscode-foreground);
margin: 0;
margin-bottom: 13px;
}

h2 {
font-size: 19px;
margin: 0;
margin-bottom: 10px;
}

h1,
h2,
h3 {
font-weight: normal;
}

div {
width: 100%;
}

/* Adjust margin of first item in markdown cell */
*:first-child {
margin-top: 0px;
}

/* h1 tags don't need top margin */
h1:first-child {
margin-top: 0;
}

/* Removes bottom margin when only one item exists in markdown cell */
*:only-child,
*:last-child {
margin-bottom: 0;
padding-bottom: 0;
}

/* makes all markdown cells consistent */
div {
min-height: ${this.options.previewNodePadding * 2}px;
}

table {
border-collapse: collapse;
border-spacing: 0;
}

table th,
table td {
border: 1px solid;
}

table > thead > tr > th {
text-align: left;
border-bottom: 1px solid;
}

table > thead > tr > th,
table > thead > tr > td,
table > tbody > tr > th,
table > tbody > tr > td {
padding: 5px 10px;
}

table > tbody > tr + tr > td {
border-top: 1px solid;
}

blockquote {
margin: 0 7px 0 5px;
padding: 0 16px 0 10px;
border-left-width: 5px;
border-left-style: solid;
}

code,
.code {
font-family: var(--monaco-monospace-font);
font-size: 1em;
line-height: 1.357em;
}

.code {
white-space: pre-wrap;
}

.latex-block {
display: block;
}

.latex {
vertical-align: middle;
display: inline-block;
}

.latex img,
.latex-block img {
filter: brightness(0) invert(0)
}

dragging {
background-color: var(--vscode-editor-background);
}
</style>
</template>
<style>
#container > div > div.output {
width: calc(100% - ${this.options.leftMargin + (this.options.cellMargin * 2) + this.options.runGutter}px);
Expand Down Expand Up @@ -447,140 +593,6 @@ export class BackLayerWebView<T extends ICommonCellInfo> extends Disposable {
background: var(--vscode-notebook-selectedCellBackground);
}

#container > div > div.preview img {
max-width: 100%;
max-height: 100%;
}

#container > div > div.preview a {
text-decoration: none;
}

#container > div > div.preview a:hover {
text-decoration: underline;
}

#container > div > div.preview a:focus,
#container > div > div.preview input:focus,
#container > div > div.preview select:focus,
#container > div > div.preview textarea:focus {
outline: 1px solid -webkit-focus-ring-color;
outline-offset: -1px;
}

#container > div > div.preview hr {
border: 0;
height: 2px;
border-bottom: 2px solid;
}

#container > div > div.preview h1 {
font-size: 26px;
padding-bottom: 8px;
line-height: 31px;
border-bottom-width: 1px;
border-bottom-style: solid;
border-color: var(--vscode-foreground);
margin: 0;
margin-bottom: 13px;
}

#container > div > div.preview h2 {
font-size: 19px;
margin: 0;
margin-bottom: 10px;
}

#container > div > div.preview h1,
#container > div > div.preview h2,
#container > div > div.preview h3 {
font-weight: normal;
}

#container > div > div.preview div {
width: 100%;
}

/* Adjust margin of first item in markdown cell */
#container > div > div.preview *:first-child {
margin-top: 0px;
}

/* h1 tags don't need top margin */
#container > div > div.preview h1:first-child {
margin-top: 0;
}

/* Removes bottom margin when only one item exists in markdown cell */
#container > div > div.preview *:only-child,
#container > div > div.preview *:last-child {
margin-bottom: 0;
padding-bottom: 0;
}

/* makes all markdown cells consistent */
#container > div > div.preview div {
min-height: ${this.options.previewNodePadding * 2}px;
}

#container > div > div.preview table {
border-collapse: collapse;
border-spacing: 0;
}

#container > div > div.preview table th,
#container > div > div.preview table td {
border: 1px solid;
}

#container > div > div.preview table > thead > tr > th {
text-align: left;
border-bottom: 1px solid;
}

#container > div > div.preview table > thead > tr > th,
#container > div > div.preview table > thead > tr > td,
#container > div > div.preview table > tbody > tr > th,
#container > div > div.preview table > tbody > tr > td {
padding: 5px 10px;
}

#container > div > div.preview table > tbody > tr + tr > td {
border-top: 1px solid;
}

#container > div > div.preview blockquote {
margin: 0 7px 0 5px;
padding: 0 16px 0 10px;
border-left-width: 5px;
border-left-style: solid;
}

#container > div > div.preview code,
#container > div > div.preview .code {
font-family: var(--monaco-monospace-font);
font-size: 1em;
line-height: 1.357em;
}

#container > div > div.preview .code {
white-space: pre-wrap;
}

#container > div > div.preview .latex-block {
display: block;
}

#container > div > div.preview .latex {
vertical-align: middle;
display: inline-block;
}

#container > div > div.preview .latex img,
#container > div > div.preview .latex-block img {
filter: brightness(0) invert(0)
}

#container > div > div.preview.dragging {
background-color: var(--vscode-editor-background);
}
Expand Down
Expand Up @@ -48,15 +48,15 @@ function webviewPreloads() {
return;
}

for (let node = event.target as HTMLElement | null; node; node = node.parentNode as HTMLElement) {
for (const node of event.composedPath()) {
if (node instanceof HTMLAnchorElement && node.href) {
if (node.href.startsWith('blob:')) {
handleBlobUrlClick(node.href, node.download);
} else if (node.href.startsWith('data:')) {
handleDataUrl(node.href, node.download);
}
event.preventDefault();
break;
return;
}
}
};
Expand Down Expand Up @@ -748,8 +748,20 @@ function webviewPreloads() {

cellContainer.appendChild(previewContainerNode);

previewContainerNode.attachShadow({ mode: 'open' });
const previewRoot = previewContainerNode.shadowRoot! as any as HTMLElement;

// Add default webview style
const defaultStyles = document.getElementById('_defaultStyles') as HTMLStyleElement;
previewRoot.appendChild(defaultStyles.cloneNode(true));

// Add default preview style
const previewStyles = document.getElementById('preview-styles') as HTMLTemplateElement;
previewRoot.appendChild(previewStyles.content.cloneNode(true));

const previewNode = document.createElement('div');
previewContainerNode.appendChild(previewNode);
previewNode.id = 'preview';
previewRoot.appendChild(previewNode);

updateMarkdownPreview(cellId, content);

Expand All @@ -773,6 +785,10 @@ function webviewPreloads() {
return;
}

const previewRoot = previewContainerNode.shadowRoot;

const previewNode = previewRoot?.getElementById('preview') as HTMLElement;

// TODO: handle namespace
if (typeof content === 'string') {
if (content.trim().length === 0) {
Expand All @@ -781,7 +797,7 @@ function webviewPreloads() {
} else {
previewContainerNode.classList.remove('emptyMarkdownCell');
onDidCreateMarkdown.fire([undefined /* data.apiNamespace */, {
element: previewContainerNode,
element: previewNode,
content: content
}]);
}
Expand Down