@lobehub/ui
Version:
Lobe UI is an open-source UI component library for building AIGC web apps
1 lines • 4.75 kB
Source Map (JSON)
{"version":3,"file":"tokenFade.mjs","names":[],"sources":["../../../src/Highlighter/SyntaxHighlighter/tokenFade.ts"],"sourcesContent":["import { STREAM_FADE_DURATION } from '@lobehub/streamdown';\nimport type { CSSProperties } from 'react';\nimport type { ThemedToken } from 'shiki';\n\nconst MIN_GAP_MS = 16;\nconst MAX_GAP_MS = 160;\nconst MIN_CHAR_PACE_MS = 2;\nconst MAX_CHAR_PACE_MS = 18;\n\nexport interface TokenFadeStore {\n /**\n * Birth timestamp per source char. A char's birth is the birth of the\n * token it is displayed in, and it only ever moves earlier: shiki\n * re-splits the last line as it completes (`'rea` becomes `'`, `rea`,\n * `'`) and merges tokens the other way, and a char that was already on\n * screen at some opacity must never drop below it in the new token.\n */\n births: number[];\n lastCommitTs: number;\n styles: Map<number, { birth: number; style: CSSProperties | null }>;\n}\n\nexport const createTokenFadeStore = (): TokenFadeStore => ({\n births: [],\n lastCommitTs: 0,\n styles: new Map(),\n});\n\nconst clamp = (value: number, min: number, max: number) => Math.min(max, Math.max(min, value));\n\nconst RETOKENIZED_LINES = 2;\n\nexport const markTokenBirths = (\n store: TokenFadeStore,\n lines: ThemedToken[][],\n now: number,\n): number[] => {\n const lineStarts: number[] = [];\n const tokens: { length: number; offset: number }[] = [];\n let offset = 0;\n\n for (const [lineIndex, line] of lines.entries()) {\n if (lineIndex > 0) offset += 1;\n lineStarts.push(offset);\n if (lineIndex >= lines.length - RETOKENIZED_LINES) {\n for (const token of line) {\n tokens.push({ length: token.content.length, offset });\n offset += token.content.length;\n }\n } else {\n for (const token of line) offset += token.content.length;\n }\n }\n\n const { births } = store;\n const newChars = offset - births.length;\n if (newChars > 0) {\n const gapMs =\n store.lastCommitTs === 0\n ? MIN_GAP_MS\n : clamp(now - store.lastCommitTs, MIN_GAP_MS, MAX_GAP_MS);\n const pace = clamp(gapMs / newChars, MIN_CHAR_PACE_MS, MAX_CHAR_PACE_MS);\n const cap = now + gapMs + STREAM_FADE_DURATION;\n for (let i = births.length; i < offset; i++) {\n const chained = i > 0 ? births[i - 1] + pace : now;\n births.push(Math.min(cap, Math.max(chained, now)));\n }\n store.lastCommitTs = now;\n }\n\n for (const token of tokens) {\n let birth = births[token.offset];\n for (let i = token.offset + 1; i < token.offset + token.length; i++) {\n if (births[i] < birth) birth = births[i];\n }\n for (let i = token.offset; i < token.offset + token.length; i++) births[i] = birth;\n }\n\n return lineStarts;\n};\n\nexport const resolveTokenFadeStyle = (\n store: TokenFadeStore,\n offset: number,\n now: number,\n): CSSProperties | null => {\n const birth = store.births[offset];\n const cached = store.styles.get(offset);\n if (cached && cached.birth === birth) return cached.style;\n\n const elapsed = now - birth;\n const style = elapsed >= STREAM_FADE_DURATION ? null : { animationDelay: `${-elapsed}ms` };\n store.styles.set(offset, { birth, style });\n return style;\n};\n"],"mappings":";;AAIA,MAAM,aAAa;AACnB,MAAM,aAAa;AACnB,MAAM,mBAAmB;AACzB,MAAM,mBAAmB;AAezB,MAAa,8BAA8C;CACzD,QAAQ,CAAC;CACT,cAAc;CACd,wBAAQ,IAAI,IAAI;AAClB;AAEA,MAAM,SAAS,OAAe,KAAa,QAAgB,KAAK,IAAI,KAAK,KAAK,IAAI,KAAK,KAAK,CAAC;AAE7F,MAAM,oBAAoB;AAE1B,MAAa,mBACX,OACA,OACA,QACa;CACb,MAAM,aAAuB,CAAC;CAC9B,MAAM,SAA+C,CAAC;CACtD,IAAI,SAAS;CAEb,KAAK,MAAM,CAAC,WAAW,SAAS,MAAM,QAAQ,GAAG;EAC/C,IAAI,YAAY,GAAG,UAAU;EAC7B,WAAW,KAAK,MAAM;EACtB,IAAI,aAAa,MAAM,SAAS,mBAC9B,KAAK,MAAM,SAAS,MAAM;GACxB,OAAO,KAAK;IAAE,QAAQ,MAAM,QAAQ;IAAQ;GAAO,CAAC;GACpD,UAAU,MAAM,QAAQ;EAC1B;OAEA,KAAK,MAAM,SAAS,MAAM,UAAU,MAAM,QAAQ;CAEtD;CAEA,MAAM,EAAE,WAAW;CACnB,MAAM,WAAW,SAAS,OAAO;CACjC,IAAI,WAAW,GAAG;EAChB,MAAM,QACJ,MAAM,iBAAiB,IACnB,aACA,MAAM,MAAM,MAAM,cAAc,YAAY,UAAU;EAC5D,MAAM,OAAO,MAAM,QAAQ,UAAU,kBAAkB,gBAAgB;EACvE,MAAM,MAAM,MAAM,QAAQ;EAC1B,KAAK,IAAI,IAAI,OAAO,QAAQ,IAAI,QAAQ,KAAK;GAC3C,MAAM,UAAU,IAAI,IAAI,OAAO,IAAI,KAAK,OAAO;GAC/C,OAAO,KAAK,KAAK,IAAI,KAAK,KAAK,IAAI,SAAS,GAAG,CAAC,CAAC;EACnD;EACA,MAAM,eAAe;CACvB;CAEA,KAAK,MAAM,SAAS,QAAQ;EAC1B,IAAI,QAAQ,OAAO,MAAM;EACzB,KAAK,IAAI,IAAI,MAAM,SAAS,GAAG,IAAI,MAAM,SAAS,MAAM,QAAQ,KAC9D,IAAI,OAAO,KAAK,OAAO,QAAQ,OAAO;EAExC,KAAK,IAAI,IAAI,MAAM,QAAQ,IAAI,MAAM,SAAS,MAAM,QAAQ,KAAK,OAAO,KAAK;CAC/E;CAEA,OAAO;AACT;AAEA,MAAa,yBACX,OACA,QACA,QACyB;CACzB,MAAM,QAAQ,MAAM,OAAO;CAC3B,MAAM,SAAS,MAAM,OAAO,IAAI,MAAM;CACtC,IAAI,UAAU,OAAO,UAAU,OAAO,OAAO,OAAO;CAEpD,MAAM,UAAU,MAAM;CACtB,MAAM,QAAQ,WAAW,uBAAuB,OAAO,EAAE,gBAAgB,GAAG,CAAC,QAAQ,IAAI;CACzF,MAAM,OAAO,IAAI,QAAQ;EAAE;EAAO;CAAM,CAAC;CACzC,OAAO;AACT"}