Token Transitions
Animate the transition between code blocks at a token level.
content.md
```scalaobject Main {def factorial(n: Int): Int = {if (n == 0) {return 1} else {return n * factorial(n - 1)}}}``````pythondef factorial(n):if n == 0:return 1else:return n * factorial(n - 1)```
object Main {def factorial(n: Int): Int = {if (n == 0) {return 1} else {return n * factorial(n - 1)}}}
Implementation
We are going to use some utils from codehike/utils/token-transitions
. The easiest way of using them is inside a class component:
smooth-pre.tsx
"use client"import { CustomPreProps, InnerPre, getPreRef } from "codehike/code"import {TokenTransitionsSnapshot,calculateTransitions,getStartingSnapshot,} from "codehike/utils/token-transitions"import React from "react"const MAX_TRANSITION_DURATION = 900 // millisecondsexport class SmoothPre extends React.Component<CustomPreProps> {ref: React.RefObject<HTMLPreElement>constructor(props: CustomPreProps) {super(props)this.ref = getPreRef(this.props)}render() {return <InnerPre merge={this.props} style={{ position: "relative" }} />}getSnapshotBeforeUpdate() {return getStartingSnapshot(this.ref.current!)}componentDidUpdate(prevProps: never,prevState: never,snapshot: TokenTransitionsSnapshot,) {const transitions = calculateTransitions(this.ref.current!, snapshot)transitions.forEach(({ element, keyframes, options }) => {const { translateX, translateY, ...kf } = keyframes as anyif (translateX && translateY) {kf.translate = [`${translateX[0]}px ${translateY[0]}px`,`${translateX[1]}px ${translateY[1]}px`,]}element.animate(kf, {duration: options.duration * MAX_TRANSITION_DURATION,delay: options.delay * MAX_TRANSITION_DURATION,easing: options.easing,fill: "both",})})}}
Then we create the annotation handler:
code.tsx
import { AnnotationHandler, InnerToken } from "codehike/code"import { SmoothPre } from "./smooth-pre"export const tokenTransitions: AnnotationHandler = {name: "token-transitions",PreWithRef: SmoothPre,Token: (props) => (<InnerToken merge={props} style={{ display: "inline-block" }} />),}
And then pass the handler to the Pre
component:
page.tsx
async function Code({ codeblock }: { codeblock: RawCode }) {const highlighted = await highlight(codeblock, "github-dark")return <Pre code={highlighted} handlers={[tokenTransitions]} />}
When the codeblock
changes, the Code
component will animate the transition between the old and new code blocks.