Thanks to visit codestin.com
Credit goes to codehike.org

Focus

Focus blocks of code. Dim the unfocused code. Ensure the focused code is visible when there's overflow.

Useful when you want to change a codeblock focus depending on the user's interaction.

content.md
```js
function lorem(ipsum, dolor = 1) {
const sit = ipsum == null ? 0 : ipsum.sit
dolor = sit - amet(dolor)
return sit ? consectetur(ipsum) : []
}
function ipsum(ipsum, dolor = 1) {
return dolor
}
// !focus(1:5)
function dolor(ipsum, dolor = 1) {
const sit = ipsum == null ? 0 : ipsum.sit
dolor = sit - amet(dolor)
return sit ? consectetur(ipsum) : []
}
```
function lorem(ipsum, dolor = 1) {
const sit = ipsum == null ? 0 : ipsum.sit
dolor = sit - amet(dolor)
return sit ? consectetur(ipsum) : []
}
function ipsum(ipsum, dolor = 1) {
return dolor
}
function dolor(ipsum, dolor = 1) {
const sit = ipsum == null ? 0 : ipsum.sit
dolor = sit - amet(dolor)
return sit ? consectetur(ipsum) : []
}
You can also change the focus annotations on a rendered codeblock:

Implementation

We need two things:

  • Set a data-focus={true} to the focused lines
  • Get a ref of the pre element, and scroll it if needed
focus.tsx
import { AnnotationHandler, InnerLine } from "codehike/code"
import { PreWithFocus } from "./focus.client"
export const focus: AnnotationHandler = {
name: "focus",
onlyIfAnnotated: true,
PreWithRef: PreWithFocus,
Line: (props) => (
<InnerLine
merge={props}
className=""
/>
),
AnnotatedLine: ({ annotation, ...props }) => (
<InnerLine merge={props} data-focus={true} className="" />
),
}
focus.client.tsx
"use client"
import React, { useLayoutEffect, useRef } from "react"
import { AnnotationHandler, InnerPre, getPreRef } from "codehike/code"
export const PreWithFocus: AnnotationHandler["PreWithRef"] = (props) => {
const ref = getPreRef(props)
useScrollToFocus(ref)
return <InnerPre merge={props} />
}
function useScrollToFocus(ref: React.RefObject<HTMLPreElement>) {
const firstRender = useRef(true)
useLayoutEffect(() => {
if (ref.current) {
// find all descendants whith data-focus="true"
const focusedElements = ref.current.querySelectorAll(
"[data-focus=true]",
) as NodeListOf<HTMLElement>
// find top and bottom of the focused elements
const containerRect = ref.current.getBoundingClientRect()
let top = Infinity
let bottom = -Infinity
focusedElements.forEach((el) => {
const rect = el.getBoundingClientRect()
top = Math.min(top, rect.top - containerRect.top)
bottom = Math.max(bottom, rect.bottom - containerRect.top)
})
// scroll to the focused elements if any part of them is not visible
if (bottom > containerRect.height || top < 0) {
ref.current.scrollTo({
top: ref.current.scrollTop + top - 10,
behavior: firstRender.current ? "instant" : "smooth",
})
}
firstRender.current = false
}
})
}