diff --git a/lib/datatip-manager.js b/lib/datatip-manager.js index 4b5144f..8ca6e77 100644 --- a/lib/datatip-manager.js +++ b/lib/datatip-manager.js @@ -304,14 +304,14 @@ module.exports = class DatatipManager { this.currentMarkerRange = datatip.range; if (datatip.component){ - const dataTipView = new DataTipView({ reactView: datatip.component }); + const dataTipView = new DataTipView({ component: datatip.component }); this.dataTipMarkerDisposables = this.mountDataTipWithMarker(editor, datatip.range, position, dataTipView); } else if (datatip.markedStrings.length > 0) { const grammar = editor.getGrammar().name.toLowerCase(); - const htmlString = this.makeHtmlFromMarkedStrings(datatip.markedStrings, grammar); - const html = await this.renderer.render(htmlString, grammar); - const dataTipView = new DataTipView({ htmlView: html }); + const snippetHtml = await this.getSnippetHtml(datatip.markedStrings.filter(t => t.type === 'snippet').map(t => t.value).shift(), grammar); + const documentationHtml = await this.getDocumentationHtml(datatip.markedStrings.filter(t => t.type === 'markdown').map(t => t.value).shift(), grammar); + const dataTipView = new DataTipView({ snippet: snippetHtml, html: documentationHtml }); this.dataTipMarkerDisposables = this.mountDataTipWithMarker(editor, datatip.range, position, dataTipView, DataTipAlignments.BELOW); } } @@ -321,28 +321,26 @@ module.exports = class DatatipManager { } } - /** - * [makeHtmlFromMarkedStrings description] - * @param {[type]} markedStrings [description] - * @param {String} grammarName [description] - * @return {String} [description] - */ - makeHtmlFromMarkedStrings(markedStrings, grammarName) { - const regExpLSPPrefix = /^\((method|property|parameter|alias)\)\W/; - - return markedStrings.map(string => { - if (string.type === 'markdown') { - return (string.value.length > 0 ? `

${string.value}

` : null); - } else if (string.type === 'snippet') { - const snippet = string.value.replace(regExpLSPPrefix, ''); - const preElem = document.createElement('pre'); - const codeElem = document.createElement('code'); - codeElem.classList.add(grammarName); - codeElem.innerText = snippet; - preElem.appendChild(codeElem); - return preElem.outerHTML; - } - }).join(''); + async getSnippetHtml(snippet, grammarName) { + if ((snippet !== undefined) && (snippet.length > 0)) { + const regExpLSPPrefix = /^\((method|property|parameter|alias)\)\W/; + const preElem = document.createElement('pre'); + const codeElem = document.createElement('code'); + + codeElem.classList.add(grammarName); + codeElem.innerText = snippet.replace(regExpLSPPrefix, ''); + preElem.appendChild(codeElem); + + return this.renderer.render(preElem.outerHTML, grammarName); + } + return null; + } + + async getDocumentationHtml(markdownText, grammarName) { + if ((markdownText !== undefined) && (markdownText.length > 0)) { + return this.renderer.render(`

${markdownText}

`, grammarName); + } + return null; } /** diff --git a/lib/datatip-view.js b/lib/datatip-view.js index 6c8704e..1dd90e4 100644 --- a/lib/datatip-view.js +++ b/lib/datatip-view.js @@ -33,53 +33,58 @@ class HtmlView { } } +class SnippetView { + constructor({ snippet }) { + this.rootElement = document.createElement('div'); + this.rootElement.className = "datatip-container"; + if (snippet) { + this.rootElement.innerHTML = domPurify.sanitize(snippet); + } + } + + get element() { + return this.rootElement; + } +} + class ReactView { constructor({ component }) { - this.rootElement = document.createElement('span') + this.rootElement = document.createElement('span'); if (component) { - this.rootElement.innerHTML = domPurify.sanitize(ReactDOMServer.renderToStaticMarkup(component())) + this.rootElement.innerHTML = domPurify.sanitize(ReactDOMServer.renderToStaticMarkup(component())); } } get element() { - return this.rootElement + return this.rootElement; } } module.exports = class DataTipView { // Required: Define an ordinary constructor to initialize your component. - constructor(properties) { + constructor(properties, children) { this.properties = properties; + this.children = children || []; + this.updateChildren(); + etch.initialize(this); } render() { - if (this.properties.reactView) { - return ( -
- -
- ); - } - else if (this.properties.htmlView) { - return ( -
- -
- ); - } - else { - return ( -
- { this.children } -
- ); - } + return ( +
+ {this.children} +
+ ); } update(props, children) { // perform custom update logic here... // then call `etch.update`, which is async and returns a promise + this.properties = props; + this.children = children || []; + this.updateChildren(); + return etch.update(this) } @@ -89,4 +94,17 @@ module.exports = class DataTipView { await etch.destroy(this) // then perform custom teardown logic here... } + + updateChildren() { + const { component, snippet, html} = this.properties; + if (component) { + this.children.push(); + } + if (snippet) { + this.children.push(); + } + if (html) { + this.children.push(); + } + } } diff --git a/lib/main.js b/lib/main.js index 579aa13..61d083d 100644 --- a/lib/main.js +++ b/lib/main.js @@ -58,6 +58,10 @@ module.exports = { return this.datatipManager; }, + /** + * retrieves a reference to the markdown rendering service that should be used + * @param {[type]} renderer [description] + */ consumeMarkdownRenderer(renderer) { this.renderer = renderer; } diff --git a/styles/atom-ide-datatips-marked.less b/styles/atom-ide-datatips-marked.less index 0f54df3..39b4272 100644 --- a/styles/atom-ide-datatips-marked.less +++ b/styles/atom-ide-datatips-marked.less @@ -9,7 +9,7 @@ color: @syntax-text-color; font-family: var(--editor-font-family); font-size: var(--editor-font-size); - max-height: 480px; + max-height: 400px; max-width: 64em; overflow: auto; white-space: normal; diff --git a/styles/atom-ide-datatips.less b/styles/atom-ide-datatips.less index b116b7e..02e25c7 100644 --- a/styles/atom-ide-datatips.less +++ b/styles/atom-ide-datatips.less @@ -32,16 +32,23 @@ } .datatip-container { - background-color: @syntax-background-color; - display: flex; - position: relative; - max-height: 480px; - max-width: 64em; - transition: background-color 0.15s ease; - padding: 8px; - white-space: pre-wrap; + color: @syntax-text-color; font-family: var(--editor-font-family); font-size: var(--editor-font-size); + max-height: 480px; + max-width: 64em; + overflow: auto; + white-space: normal; + + // Avoid excess internal padding from markdown blocks. + :first-child { + margin-top: 0; + } + + :last-child { + margin-bottom: 0; + } + &:hover { background-color: mix(@syntax-background-color, @syntax-selection-color, 50%); } @@ -49,6 +56,13 @@ &:not(:last-of-type) { border-bottom: 1px solid fade(@syntax-cursor-color, 10%); } + + pre { + font-family: var(--editor-font-family); + font-size: var(--editor-font-size); + margin-bottom: 8px; + border-radius: 0; + } } .datatip-content {