UNPKG

@nvq/flowtoken

Version:

Animated React components for streaming text and markdown with GitHub theme syntax highlighting (forked from flowtoken)

134 lines (133 loc) 6.18 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const react_1 = __importDefault(require("react")); // Custom hook for dark mode detection const useDarkMode = () => { const [isDark, setIsDark] = react_1.default.useState(false); react_1.default.useEffect(() => { const checkDarkMode = () => { // Detect Storybook dark mode toggle const htmlElement = document.documentElement; const isDarkMode = htmlElement.classList.contains("dark"); setIsDark(isDarkMode); }; // Initial check checkDarkMode(); // Monitor class changes with MutationObserver const observer = new MutationObserver(checkDarkMode); observer.observe(document.documentElement, { attributes: true, attributeFilter: ["class"], }); return () => observer.disconnect(); }, []); return isDark; }; // Custom renderer for SHIKI (based on original customCodeRenderer animation logic) const ShikiCodeRenderer = ({ codeContent, language, animation, animationDuration, animationTimingFunction, }) => { const [renderedTokens, setRenderedTokens] = react_1.default.useState(null); const isDark = useDarkMode(); react_1.default.useEffect(() => { const renderCode = async () => { try { // Dynamic import to avoid serverExternalPackages issues const { codeToTokens, bundledLanguages } = await Promise.resolve().then(() => __importStar(require("shiki"))); // Check if language is valid, fallback to 'text' if invalid const validLanguage = language in bundledLanguages ? language : "text"; // text言語(フォールバック)の場合のみ末尾改行を除去 const isUnsupportedLanguage = !(language in bundledLanguages); const processedCode = isUnsupportedLanguage ? codeContent.trimEnd() : codeContent; // Select theme based on dark mode const selectedTheme = isDark ? "github-dark" : "github-light"; const { tokens } = await codeToTokens(processedCode, { lang: validLanguage, theme: selectedTheme, // Specify single theme }); // Apply animation logic similar to original customCodeRenderer const rendered = tokens.map((line, lineIndex) => (react_1.default.createElement("div", { key: lineIndex, style: { display: "block" } }, line.map((token, tokenIndex) => { // SHIKI's ThemedToken actually only has color property const tokenStyles = { color: token.color || (isDark ? "#e6edf3" : "#24292f"), // Theme default color when undefined }; // Apply animation to each word like original customCodeRenderer return (react_1.default.createElement("span", { key: tokenIndex, style: tokenStyles }, token.content .split(" ") .map((word, wordIndex) => (react_1.default.createElement("span", { key: wordIndex, style: { animationName: animation || "", animationDuration, animationTimingFunction, animationIterationCount: 1, whiteSpace: "pre-wrap", display: "inline-block", } }, word + (wordIndex < token.content.split(" ").length - 1 ? " " : "")))))); })))); setRenderedTokens(rendered); } catch (error) { console.warn(`Failed to render code for language: ${language}`, error); setRenderedTokens(`Error rendering code: ${error}`); } }; renderCode(); }, [ codeContent, language, animation, animationDuration, animationTimingFunction, isDark, // Re-render when dark mode changes ]); return (react_1.default.createElement("pre", { style: { margin: 0, padding: "1rem", background: "transparent", fontSize: "0.775rem", overflow: "auto", borderRadius: "0 0 0.75rem 0.75rem", // rounded-b-xl } }, react_1.default.createElement("code", null, renderedTokens))); }; exports.default = ShikiCodeRenderer;