UNPKG

@ant-design/x

Version:

Craft AI-driven interfaces effortlessly

159 lines (151 loc) 5.39 kB
import _extends from "@babel/runtime/helpers/esm/extends"; import { clsx } from 'clsx'; import React, { lazy, Suspense } from 'react'; import { PrismLight as SyntaxHighlighter } from 'react-syntax-highlighter'; import { oneLight } from 'react-syntax-highlighter/dist/esm/styles/prism'; import useXComponentConfig from "../_util/hooks/use-x-component-config"; import Actions from "../actions"; import { useXProviderContext } from "../x-provider"; import useStyle from "./style"; const customOneLight = { ...oneLight, 'pre[class*="language-"]': { ...oneLight['pre[class*="language-"]'], margin: 0 } }; // Module-level cache for loaded language highlighters const highlighterCache = new Map(); // Full Prism highlighter (cached, loaded on demand) let FullPrismHighlighter = null; const getAsyncHighlighter = lang => { if (!highlighterCache.has(lang)) { const LazyHighlighter = /*#__PURE__*/lazy(async () => { try { await import(`react-syntax-highlighter/dist/esm/languages/prism/${lang}`); } catch (error) { console.warn(`[CodeHighlighter] Failed to load language: ${lang}`, error); } return { default: ({ children, ...rest }) => /*#__PURE__*/React.createElement(SyntaxHighlighter, _extends({ language: lang }, rest), children) }; }); highlighterCache.set(lang, LazyHighlighter); } return highlighterCache.get(lang); }; const getFullPrismHighlighter = () => { if (!FullPrismHighlighter) { FullPrismHighlighter = /*#__PURE__*/lazy(() => import('react-syntax-highlighter').then(module => ({ default: props => /*#__PURE__*/React.createElement(module.Prism, props) }))); } return FullPrismHighlighter; }; const CodeHighlighter = /*#__PURE__*/React.forwardRef((props, ref) => { const { lang, children, header, prefixCls: customizePrefixCls, className, classNames = {}, styles = {}, style = {}, highlightProps, prismLightMode = true, ...restProps } = props; // ============================ Prefix ============================ const { getPrefixCls, direction } = useXProviderContext(); const prefixCls = getPrefixCls('codeHighlighter', customizePrefixCls); const [hashId, cssVarCls] = useStyle(prefixCls); const contextConfig = useXComponentConfig('codeHighlighter'); // Get the appropriate highlighter component // - prismLightMode = true (default): Use PrismLight with async language loading // - prismLightMode = false: Use full Prism (all languages included) const Highlighter = prismLightMode ? lang ? getAsyncHighlighter(lang) : SyntaxHighlighter : getFullPrismHighlighter(); // ============================ Early Returns ============================ if (!children) { return null; } // No lang means no highlighting needed, return plain code directly if (!lang) { return /*#__PURE__*/React.createElement("code", null, children); } // ============================ style ============================ const mergedCls = clsx(prefixCls, contextConfig.className, className, contextConfig.classNames?.root, classNames.root, hashId, cssVarCls, { [`${prefixCls}-rtl`]: direction === 'rtl' }); const mergedStyle = { ...contextConfig.style, ...styles?.root, ...style }; // ============================ render header ============================ const renderHeader = () => { if (header === undefined) { return /*#__PURE__*/React.createElement("div", { className: clsx(`${prefixCls}-header`, contextConfig.classNames?.header, classNames.header), style: { ...contextConfig.styles?.header, ...styles.header } }, /*#__PURE__*/React.createElement("span", { className: clsx(`${prefixCls}-header-title`, classNames.headerTitle, contextConfig.classNames?.headerTitle), style: { ...contextConfig.styles?.headerTitle, ...styles.headerTitle } }, lang), /*#__PURE__*/React.createElement(Actions.Copy, { text: children })); } const headerResult = typeof header === 'function' ? header() : header; if (headerResult === false) { return null; } return headerResult; }; // ============================ render ============================ const codeElement = /*#__PURE__*/React.createElement(Highlighter, _extends({ language: lang, wrapLines: true, style: customOneLight, codeTagProps: { style: { background: 'transparent' } } }, highlightProps), children.replace(/\n$/, '')); const highlightedCode = /*#__PURE__*/React.createElement(Suspense, { fallback: /*#__PURE__*/React.createElement("code", { style: { whiteSpace: 'pre-wrap' } }, children.replace(/\n$/, '')) }, codeElement); return /*#__PURE__*/React.createElement("div", _extends({ ref: ref, className: mergedCls, style: mergedStyle }, restProps), renderHeader(), /*#__PURE__*/React.createElement("div", { className: clsx(`${prefixCls}-code`, contextConfig.classNames?.code, classNames.code), style: { ...contextConfig.styles.code, ...styles.code } }, highlightedCode)); }); if (process.env.NODE_ENV !== 'production') { CodeHighlighter.displayName = 'CodeHighlighter'; } export default CodeHighlighter;