{"version":3,"file":"StreamRenderer.mjs","names":[],"sources":["../../../src/Highlighter/SyntaxHighlighter/StreamRenderer.tsx"],"sourcesContent":["'use client';\n\nimport { getTokenStyleObject } from '@shikijs/core';\nimport { cx } from 'antd-style';\nimport type { CSSProperties } from 'react';\nimport { memo, useRef } from 'react';\nimport type { BuiltinTheme, ThemedToken } from 'shiki';\n\nimport { useStreamHighlight } from '@/hooks/useStreamHighlight';\n\nimport {\n  createTokenFadeStore,\n  markTokenBirths,\n  resolveTokenFadeStyle,\n  type TokenFadeStore,\n} from './tokenFade';\n\ninterface StreamRendererProps {\n  children: string;\n  className?: string;\n  enableTransformer?: boolean;\n  fallbackClassName?: string;\n  language: string;\n  style?: CSSProperties;\n  theme?: BuiltinTheme;\n}\n\nconst normalizeStyleKeys = (style: Record<string, string | number>): CSSProperties => {\n  const normalized: CSSProperties = {};\n  Object.entries(style).forEach(([key, value]) => {\n    const normalizedKey = key.replaceAll(/-([a-z])/g, (_, char) => char.toUpperCase());\n    (normalized as Record<string, string | number>)[normalizedKey] = value;\n  });\n  return normalized;\n};\n\nconst getTokenInlineStyle = (token: ThemedToken): CSSProperties => {\n  const rawStyle = token.htmlStyle || getTokenStyleObject(token);\n  const baseStyle = normalizeStyleKeys(rawStyle);\n  return { ...baseStyle, whiteSpace: 'pre' };\n};\n\nconst TokenSpan = memo(\n  ({ fadeStyle, token }: { fadeStyle?: CSSProperties | null; token: ThemedToken }) => {\n    const style = fadeStyle\n      ? { ...getTokenInlineStyle(token), ...fadeStyle }\n      : getTokenInlineStyle(token);\n    return (\n      <span className={fadeStyle ? 'stream-char' : undefined} style={style}>\n        {token.content}\n      </span>\n    );\n  },\n  (prev, next) => prev.token === next.token && prev.fadeStyle === next.fadeStyle,\n);\n\nconst TokenLine = memo(\n  ({\n    fade,\n    line,\n    now,\n    start,\n  }: {\n    fade: TokenFadeStore;\n    line: ThemedToken[];\n    now: number;\n    start: number;\n  }) => {\n    if (!line.length) {\n      return (\n        <span className=\"line\">\n          <span style={{ whiteSpace: 'pre' }}>{'\\u00A0'}</span>\n        </span>\n      );\n    }\n\n    let offset = start;\n    return (\n      <span className=\"line\">\n        {line.map((token) => {\n          const tokenOffset = offset;\n          offset += token.content.length;\n          return (\n            <TokenSpan\n              fadeStyle={resolveTokenFadeStyle(fade, tokenOffset, now)}\n              key={tokenOffset}\n              token={token}\n            />\n          );\n        })}\n      </span>\n    );\n  },\n  (prev, next) => prev.line === next.line && prev.start === next.start,\n);\n\nconst StreamRenderer = memo<StreamRendererProps>(\n  ({ children, className, enableTransformer, fallbackClassName, language, style, theme }) => {\n    // Safely handle empty or invalid children\n    const safeChildren = children ?? '';\n\n    const streaming = useStreamHighlight(safeChildren, {\n      enableTransformer,\n      language,\n      streaming: true,\n      theme,\n    });\n\n    const lines = streaming?.lines;\n    const preStyle = streaming?.preStyle;\n\n    const fadeRef = useRef<TokenFadeStore>(createTokenFadeStore());\n    const previousTextRef = useRef('');\n    if (!safeChildren.startsWith(previousTextRef.current)) {\n      fadeRef.current = createTokenFadeStore();\n    }\n    previousTextRef.current = safeChildren;\n    const now = performance.now();\n    const lineStarts = lines ? markTokenBirths(fadeRef.current, lines, now) : [];\n\n    if (!lines || lines.length === 0) {\n      return (\n        <div className={fallbackClassName} dir=\"ltr\" style={style}>\n          <pre>\n            <code>{safeChildren}</code>\n          </pre>\n        </div>\n      );\n    }\n\n    return (\n      <div className={className} dir=\"ltr\" style={style}>\n        <pre className={cx('shiki', theme)} style={preStyle} tabIndex={0}>\n          <code style={{ display: 'flex', flexDirection: 'column', whiteSpace: 'pre' }}>\n            {lines.map((line, index) => (\n              <TokenLine\n                fade={fadeRef.current}\n                key={`line-${index}`}\n                line={line}\n                now={now}\n                start={lineStarts[index]}\n              />\n            ))}\n          </code>\n        </pre>\n      </div>\n    );\n  },\n);\n\nStreamRenderer.displayName = 'StreamRenderer';\n\nexport default StreamRenderer;\n"],"mappings":";;;;;;;;AA2BA,MAAM,sBAAsB,UAA0D;CACpF,MAAM,aAA4B,CAAC;CACnC,OAAO,QAAQ,KAAK,CAAC,CAAC,SAAS,CAAC,KAAK,WAAW;EAC9C,MAAM,gBAAgB,IAAI,WAAW,cAAc,GAAG,SAAS,KAAK,YAAY,CAAC;EACjF,WAAgD,iBAAiB;CACnE,CAAC;CACD,OAAO;AACT;AAEA,MAAM,uBAAuB,UAAsC;CACjE,MAAM,WAAW,MAAM,aAAa,oBAAoB,KAAK;CAE7D,OAAO;EAAE,GADS,mBAAmB,QACjB;EAAG,YAAY;CAAM;AAC3C;AAEA,MAAM,YAAY,MACf,EAAE,WAAW,YAAsE;CAClF,MAAM,QAAQ,YACV;EAAE,GAAG,oBAAoB,KAAK;EAAG,GAAG;CAAU,IAC9C,oBAAoB,KAAK;CAC7B,OACE,oBAAC,QAAD;EAAM,WAAW,YAAY,gBAAgB,KAAA;EAAkB;EAC5D,UAAA,MAAM;CACH,CAAA;AAEV,IACC,MAAM,SAAS,KAAK,UAAU,KAAK,SAAS,KAAK,cAAc,KAAK,SACvE;AAEA,MAAM,YAAY,MACf,EACC,MACA,MACA,KACA,YAMI;CACJ,IAAI,CAAC,KAAK,QACR,OACE,oBAAC,QAAD;EAAM,WAAU;EACd,UAAA,oBAAC,QAAD;GAAM,OAAO,EAAE,YAAY,MAAM;GAAI,UAAA;EAAe,CAAA;CAChD,CAAA;CAIV,IAAI,SAAS;CACb,OACE,oBAAC,QAAD;EAAM,WAAU;EACb,UAAA,KAAK,KAAK,UAAU;GACnB,MAAM,cAAc;GACpB,UAAU,MAAM,QAAQ;GACxB,OACE,oBAAC,WAAD;IACE,WAAW,sBAAsB,MAAM,aAAa,GAAG;IAEhD;GACR,GAFM,WAEN;EAEL,CAAC;CACG,CAAA;AAEV,IACC,MAAM,SAAS,KAAK,SAAS,KAAK,QAAQ,KAAK,UAAU,KAAK,KACjE;AAEA,MAAM,iBAAiB,MACpB,EAAE,UAAU,WAAW,mBAAmB,mBAAmB,UAAU,OAAO,YAAY;CAEzF,MAAM,eAAe,YAAY;CAEjC,MAAM,YAAY,mBAAmB,cAAc;EACjD;EACA;EACA,WAAW;EACX;CACF,CAAC;CAED,MAAM,QAAQ,WAAW;CACzB,MAAM,WAAW,WAAW;CAE5B,MAAM,UAAU,OAAuB,qBAAqB,CAAC;CAC7D,MAAM,kBAAkB,OAAO,EAAE;CACjC,IAAI,CAAC,aAAa,WAAW,gBAAgB,OAAO,GAClD,QAAQ,UAAU,qBAAqB;CAEzC,gBAAgB,UAAU;CAC1B,MAAM,MAAM,YAAY,IAAI;CAC5B,MAAM,aAAa,QAAQ,gBAAgB,QAAQ,SAAS,OAAO,GAAG,IAAI,CAAC;CAE3E,IAAI,CAAC,SAAS,MAAM,WAAW,GAC7B,OACE,oBAAC,OAAD;EAAK,WAAW;EAAmB,KAAI;EAAa;EAClD,UAAA,oBAAC,OAAD,EAAA,UACE,oBAAC,QAAD,EAAA,UAAO,aAAmB,CAAA,EACvB,CAAA;CACF,CAAA;CAIT,OACE,oBAAC,OAAD;EAAgB;EAAW,KAAI;EAAa;EAC1C,UAAA,oBAAC,OAAD;GAAK,WAAW,GAAG,SAAS,KAAK;GAAG,OAAO;GAAU,UAAU;GAC7D,UAAA,oBAAC,QAAD;IAAM,OAAO;KAAE,SAAS;KAAQ,eAAe;KAAU,YAAY;IAAM;IACxE,UAAA,MAAM,KAAK,MAAM,UAChB,oBAAC,WAAD;KACE,MAAM,QAAQ;KAER;KACD;KACL,OAAO,WAAW;IACnB,GAJM,QAAQ,OAId,CACF;GACG,CAAA;EACH,CAAA;CACF,CAAA;AAET,CACF;AAEA,eAAe,cAAc"}