File size: 1,590 Bytes
c16e487
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
// Reference https://github.com/bytedance/deer-flow/blob/main/web/src/core/rehype/rehype-split-words-into-spans.ts
import type { Element, Root, ElementContent } from "hast";
import { visit } from "unist-util-visit";
import type { BuildVisitor } from "unist-util-visit";

export function animateText(locale: string = "zh") {
  return (tree: Root) => {
    if (tree) {
      visit(tree, "element", ((node: Element) => {
        if (
          ["p", "h1", "h2", "h3", "h4", "h5", "h6", "li", "strong"].includes(
            node.tagName
          ) &&
          node.children
        ) {
          const newChildren: Array<ElementContent> = [];
          node.children.forEach((child) => {
            if (child.type === "text") {
              const segmenter = new Intl.Segmenter(locale, {
                granularity: "word",
              });
              const segments = segmenter.segment(child.value);
              const words = Array.from(segments)
                .map((segment) => segment.segment)
                .filter(Boolean);
              words.forEach((word: string) => {
                newChildren.push({
                  type: "element",
                  tagName: "span",
                  properties: {
                    className: "animate-fade-in",
                  },
                  children: [{ type: "text", value: word }],
                });
              });
            } else {
              newChildren.push(child);
            }
          });
          node.children = newChildren;
        }
      }) as BuildVisitor<Root, "element">);
    }
  };
}