feat: consolidate syntax highlighting code into standalone plugin (#9783)
This commit is contained in:
@@ -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"
|
||||
}
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
25
src/core/plugins/syntax-highlighting/after-load.js
Normal file
25
src/core/plugins/syntax-highlighting/after-load.js
Normal 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
|
||||
@@ -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
|
||||
@@ -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
|
||||
20
src/core/plugins/syntax-highlighting/index.js
Normal file
20
src/core/plugins/syntax-highlighting/index.js
Normal 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
|
||||
22
src/core/plugins/syntax-highlighting/root-injects.js
Normal file
22
src/core/plugins/syntax-highlighting/root-injects.js
Normal 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
|
||||
Reference in New Issue
Block a user