feat: consolidate syntax highlighting code into standalone plugin (#9783)

This commit is contained in:
Vladimír Gorej
2024-04-05 21:12:25 +02:00
committed by GitHub
parent f844319188
commit 7260005bd8
20 changed files with 231 additions and 113 deletions

View File

@@ -71,7 +71,7 @@ const RequestBody = ({
const Markdown = getComponent("Markdown", true)
const ModelExample = getComponent("modelExample")
const RequestBodyEditor = getComponent("RequestBodyEditor")
const HighlightCode = getComponent("highlightCode")
const HighlightCode = getComponent("HighlightCode", true)
const ExamplesSelectValueRetainer = getComponent("ExamplesSelectValueRetainer")
const Example = getComponent("Example")
const ParameterIncludeEmpty = getComponent("ParameterIncludeEmpty")
@@ -152,7 +152,7 @@ const RequestBody = ({
{
Map.isMap(bodyProperties) && bodyProperties.entrySeq().map(([key, schema]) => {
if (schema.get("readOnly")) return
const oneOf = schema.get("oneOf")?.get(0)?.toJS()
const anyOf = schema.get("anyOf")?.get(0)?.toJS()
schema = fromJS(fn.mergeJsonSchema(schema.toJS(), oneOf ?? anyOf ?? {}))
@@ -169,7 +169,7 @@ const RequestBody = ({
let initialValue = fn.getSampleSchema(schema, false, {
includeWriteOnly: true
})
if (initialValue === false) {
initialValue = "false"
}

View File

@@ -3,7 +3,6 @@ import PropTypes from "prop-types"
import get from "lodash/get"
import isFunction from "lodash/isFunction"
import { CopyToClipboard } from "react-copy-to-clipboard"
import { SyntaxHighlighter, getStyle } from "core/syntax-highlighting"
const style = {
cursor: "pointer",
@@ -42,6 +41,7 @@ const RequestSnippets = ({ request, requestSnippetsSelectors, getConfigs, getCom
const ArrowIcon = getComponent("ArrowUpIcon")
const ArrowDownIcon = getComponent("ArrowDownIcon")
const SyntaxHighlighter = getComponent("SyntaxHighlighter", true)
const [activeLanguage, setActiveLanguage] = useState(requestSnippetsSelectors.getSnippetGenerators()?.keySeq().first())
const [isExpanded, setIsExpanded] = useState(requestSnippetsSelectors?.getDefaultExpanded())
@@ -99,16 +99,16 @@ const RequestSnippets = ({ request, requestSnippetsSelectors, getConfigs, getCom
}
}
const SnippetComponent = canSyntaxHighlight
? <SyntaxHighlighter
const SnippetComponent = canSyntaxHighlight ? (
<SyntaxHighlighter
language={activeGenerator.get("syntax")}
className="curl microlight"
style={getStyle(get(config, "syntaxHighlight.theme"))}
>
{snippet}
</SyntaxHighlighter>
:
) : (
<textarea readOnly={true} className="curl" value={snippet}></textarea>
)
return (
<div className="request-snippets" ref={rootRef}>
@@ -147,7 +147,7 @@ const RequestSnippets = ({ request, requestSnippetsSelectors, getConfigs, getCom
</div>
}
</div>
)
)
}
RequestSnippets.propTypes = {

View File

@@ -0,0 +1,25 @@
/**
* @prettier
*/
import SyntaxHighlighter from "react-syntax-highlighter/dist/esm/light"
import js from "react-syntax-highlighter/dist/esm/languages/hljs/javascript"
import json from "react-syntax-highlighter/dist/esm/languages/hljs/json"
import xml from "react-syntax-highlighter/dist/esm/languages/hljs/xml"
import bash from "react-syntax-highlighter/dist/esm/languages/hljs/bash"
import yaml from "react-syntax-highlighter/dist/esm/languages/hljs/yaml"
import http from "react-syntax-highlighter/dist/esm/languages/hljs/http"
import powershell from "react-syntax-highlighter/dist/esm/languages/hljs/powershell"
import javascript from "react-syntax-highlighter/dist/esm/languages/hljs/javascript"
const afterLoad = () => {
SyntaxHighlighter.registerLanguage("json", json)
SyntaxHighlighter.registerLanguage("js", js)
SyntaxHighlighter.registerLanguage("xml", xml)
SyntaxHighlighter.registerLanguage("yaml", yaml)
SyntaxHighlighter.registerLanguage("http", http)
SyntaxHighlighter.registerLanguage("bash", bash)
SyntaxHighlighter.registerLanguage("powershell", powershell)
SyntaxHighlighter.registerLanguage("javascript", javascript)
}
export default afterLoad

View File

@@ -0,0 +1,116 @@
/**
* @prettier
*/
import React, { useRef, useEffect } from "react"
import PropTypes from "prop-types"
import classNames from "classnames"
import get from "lodash/get"
import saveAs from "js-file-download"
import { CopyToClipboard } from "react-copy-to-clipboard"
const HighlightCode = ({
value,
fileName = "response.txt",
className,
downloadable,
getConfigs,
getComponent,
canCopy,
language,
}) => {
const config = getConfigs()
const canSyntaxHighlight =
get(config, "syntaxHighlight") !== false &&
get(config, "syntaxHighlight.activated", true)
const rootRef = useRef(null)
const SyntaxHighlighter = getComponent("SyntaxHighlighter", true)
const handleDownload = () => {
saveAs(value, fileName)
}
const handlePreventYScrollingBeyondElement = (e) => {
const { target, deltaY } = e
const {
scrollHeight: contentHeight,
offsetHeight: visibleHeight,
scrollTop,
} = target
const scrollOffset = visibleHeight + scrollTop
const isElementScrollable = contentHeight > visibleHeight
const isScrollingPastTop = scrollTop === 0 && deltaY < 0
const isScrollingPastBottom = scrollOffset >= contentHeight && deltaY > 0
if (isElementScrollable && (isScrollingPastTop || isScrollingPastBottom)) {
e.preventDefault()
}
}
useEffect(() => {
const childNodes = Array.from(rootRef.current.childNodes).filter(
(node) => !!node.nodeType && node.classList.contains("microlight")
)
// eslint-disable-next-line no-use-before-define
childNodes.forEach((node) =>
node.addEventListener(
"mousewheel",
handlePreventYScrollingBeyondElement,
{ passive: false }
)
)
return () => {
// eslint-disable-next-line no-use-before-define
childNodes.forEach((node) =>
node.removeEventListener(
"mousewheel",
handlePreventYScrollingBeyondElement
)
)
}
}, [value, className, language])
return (
<div className="highlight-code" ref={rootRef}>
{canCopy && (
<div className="copy-to-clipboard">
<CopyToClipboard text={value}>
<button />
</CopyToClipboard>
</div>
)}
{!downloadable ? null : (
<button className="download-contents" onClick={handleDownload}>
Download
</button>
)}
{canSyntaxHighlight ? (
<SyntaxHighlighter
language={language}
className={classNames(className, "microlight")}
>
{value}
</SyntaxHighlighter>
) : (
<pre className={classNames(className, "microlight")}>{value}</pre>
)}
</div>
)
}
HighlightCode.propTypes = {
value: PropTypes.string.isRequired,
getConfigs: PropTypes.func.isRequired,
getComponent: PropTypes.func.isRequired,
className: PropTypes.string,
downloadable: PropTypes.bool,
fileName: PropTypes.string,
language: PropTypes.string,
canCopy: PropTypes.bool,
}
export default HighlightCode

View File

@@ -0,0 +1,43 @@
/**
* @prettier
*/
import React from "react"
import PropTypes from "prop-types"
import ReactSyntaxHighlighter from "react-syntax-highlighter/dist/esm/light"
import get from "lodash/get"
const SyntaxHighlighter = ({
language,
className = "",
getConfigs,
syntaxHighlighting = {},
children = null,
}) => {
const configs = getConfigs()
const theme = get(configs, "syntaxHighlight.theme")
const { styles, defaultStyle } = syntaxHighlighting
const style = styles?.[theme] ?? defaultStyle
return (
<ReactSyntaxHighlighter
language={language}
className={className}
style={style}
>
{children}
</ReactSyntaxHighlighter>
)
}
SyntaxHighlighter.propTypes = {
language: PropTypes.string.isRequired,
className: PropTypes.string,
getConfigs: PropTypes.func.isRequired,
syntaxHighlighting: PropTypes.shape({
styles: PropTypes.object,
defaultStyle: PropTypes.object,
}),
children: PropTypes.node,
}
export default SyntaxHighlighter

View File

@@ -0,0 +1,20 @@
/**
* @prettier
*/
import afterLoad from "./after-load"
import { styles, defaultStyle } from "./root-injects"
import SyntaxHighlighter from "./components/SyntaxHighlighter"
import HighlightCode from "./components/HighlightCode"
const SyntaxHighlightingPlugin = () => ({
afterLoad,
rootInjects: {
syntaxHighlighting: { styles, defaultStyle },
},
components: {
SyntaxHighlighter,
HighlightCode,
},
})
export default SyntaxHighlightingPlugin

View File

@@ -0,0 +1,22 @@
/**
* @prettier
*/
import agate from "react-syntax-highlighter/dist/esm/styles/hljs/agate"
import arta from "react-syntax-highlighter/dist/esm/styles/hljs/arta"
import monokai from "react-syntax-highlighter/dist/esm/styles/hljs/monokai"
import nord from "react-syntax-highlighter/dist/esm/styles/hljs/nord"
import obsidian from "react-syntax-highlighter/dist/esm/styles/hljs/obsidian"
import tomorrowNight from "react-syntax-highlighter/dist/esm/styles/hljs/tomorrow-night"
import idea from "react-syntax-highlighter/dist/esm/styles/hljs/idea"
export const styles = {
agate,
arta,
monokai,
nord,
obsidian,
"tomorrow-night": tomorrowNight,
idea,
}
export const defaultStyle = agate