@yuntijs/ui
Version:
☁️ Yunti UI - an open-source UI component library for building Cloud Native web apps
153 lines (151 loc) • 6.56 kB
JavaScript
import _defineProperty from "@babel/runtime/helpers/esm/defineProperty";
import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
import { getTokenStyleObject } from '@shikijs/core';
import { memo, useEffect, useRef } from 'react';
import { useStreamHighlight } from "../../hooks/useHighlight";
import { useStyles } from "./style";
import { jsx as _jsx } from "react/jsx-runtime";
var applyColorReplacement = function applyColorReplacement(color, replacements) {
if (!color || !replacements) return color;
return replacements[color.toLowerCase()] || color;
};
var normalizeStyleKeys = function normalizeStyleKeys(style) {
var normalized = {};
for (var _i = 0, _Object$entries = Object.entries(style); _i < _Object$entries.length; _i++) {
var _Object$entries$_i = _slicedToArray(_Object$entries[_i], 2),
key = _Object$entries$_i[0],
value = _Object$entries$_i[1];
var normalizedKey = key.replaceAll(/-([a-z])/g, function (_, char) {
return char.toUpperCase();
});
normalized[normalizedKey] = value;
}
return normalized;
};
var getTokenInlineStyle = function getTokenInlineStyle(token, replacements) {
var rawStyle = token.htmlStyle || getTokenStyleObject(token);
var baseStyle = normalizeStyleKeys(rawStyle);
if (!replacements) return _objectSpread({}, baseStyle);
var style = _objectSpread({}, baseStyle);
if (style.color && typeof style.color === 'string') {
style.color = applyColorReplacement(style.color, replacements);
}
if (style.backgroundColor && typeof style.backgroundColor === 'string') {
style.backgroundColor = applyColorReplacement(style.backgroundColor, replacements);
}
return style;
};
var TokenSpan = /*#__PURE__*/memo(function (_ref) {
var token = _ref.token,
replacements = _ref.replacements;
return /*#__PURE__*/_jsx("span", {
style: getTokenInlineStyle(token, replacements),
children: token.content
}, token.content);
}, function (prev, next) {
return prev.token === next.token;
});
var TokenLine = /*#__PURE__*/memo(function (_ref2) {
var line = _ref2.line,
replacements = _ref2.replacements;
if (line.length === 0) {
return /*#__PURE__*/_jsx("span", {
className: "line",
children: /*#__PURE__*/_jsx("span", {
children: "\xA0"
})
});
}
return /*#__PURE__*/_jsx("span", {
className: "line",
children: line.map(function (token, tokenIndex) {
return /*#__PURE__*/_jsx(TokenSpan, {
replacements: replacements,
token: token
}, "token-".concat(tokenIndex));
})
});
}, function (prev, next) {
return prev.line === next.line;
});
var StreamRenderer = /*#__PURE__*/memo(function (_ref3) {
var _lines$length, _lines$reduce, _lines;
var children = _ref3.children,
className = _ref3.className,
enableTransformer = _ref3.enableTransformer,
fallbackClassName = _ref3.fallbackClassName,
language = _ref3.language,
style = _ref3.style,
theme = _ref3.theme;
var _useStyles = useStyles({
theme: theme
}),
styles = _useStyles.styles,
cx = _useStyles.cx;
var safeChildren = children !== null && children !== void 0 ? children : '';
var preRef = useRef(null);
var result = useStreamHighlight(safeChildren, language, enableTransformer, theme);
var lines = result === null || result === void 0 ? void 0 : result.lines;
var replacements = result === null || result === void 0 ? void 0 : result.colorReplacements;
var linesCount = (_lines$length = lines === null || lines === void 0 ? void 0 : lines.length) !== null && _lines$length !== void 0 ? _lines$length : 0;
// 计算最后一行的内容长度,用于 wrap 模式下折行时也能触发滚动
var lastLineContentLength = linesCount > 0 ? (_lines$reduce = lines === null || lines === void 0 || (_lines = lines[linesCount - 1]) === null || _lines === void 0 ? void 0 : _lines.reduce(function (acc, token) {
var _token$content$length, _token$content;
return acc + ((_token$content$length = (_token$content = token.content) === null || _token$content === void 0 ? void 0 : _token$content.length) !== null && _token$content$length !== void 0 ? _token$content$length : 0);
}, 0)) !== null && _lines$reduce !== void 0 ? _lines$reduce : 0 : 0;
var rafIdRef = useRef(0);
// 流式输出时自动滚动(使用 RAF 节流,每帧最多执行一次)
useEffect(function () {
if (!preRef.current || linesCount === 0) return;
// 取消上一次未执行的 RAF
if (rafIdRef.current) {
cancelAnimationFrame(rafIdRef.current);
}
rafIdRef.current = requestAnimationFrame(function () {
if (!preRef.current) return;
preRef.current.scrollTop = preRef.current.scrollHeight;
});
return function () {
if (rafIdRef.current) {
cancelAnimationFrame(rafIdRef.current);
}
};
}, [linesCount, lastLineContentLength]);
if (!lines || lines.length === 0) {
return /*#__PURE__*/_jsx("div", {
className: cx(styles.shiki, fallbackClassName),
dir: "ltr",
style: style,
children: /*#__PURE__*/_jsx("pre", {
children: /*#__PURE__*/_jsx("code", {
children: safeChildren
})
})
});
}
return /*#__PURE__*/_jsx("div", {
className: cx(styles.shiki, className),
dir: "ltr",
style: style,
children: /*#__PURE__*/_jsx("pre", {
ref: preRef,
tabIndex: 0,
children: /*#__PURE__*/_jsx("code", {
style: {
display: 'flex',
flexDirection: 'column'
},
children: lines.map(function (line, index) {
return /*#__PURE__*/_jsx(TokenLine, {
line: line,
replacements: replacements
}, "line-".concat(index));
})
})
})
});
});
StreamRenderer.displayName = 'StreamRenderer';
export default StreamRenderer;