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
```jsfunction lorem(ipsum, dolor = 1) {const sit = ipsum == null ? 0 : ipsum.sitdolor = 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.sitdolor = sit - amet(dolor)return sit ? consectetur(ipsum) : []}```
function lorem(ipsum, dolor = 1) {const sit = ipsum == null ? 0 : ipsum.sitdolor = 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.sitdolor = 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 thepre
element, and scroll it if needed
focus.tsx
"use client"import {AnnotationHandler,InnerPre,getPreRef,InnerLine,} from "codehike/code"import React, { useLayoutEffect, useRef } from "react"export const focus: AnnotationHandler = {name: "focus",onlyIfAnnotated: true,PreWithRef: (props) => {const ref = getPreRef(props)useScrollToFocus(ref)return <InnerPre merge={props} />},Line: (props) => (<InnerLinemerge={props}className=""/>),AnnotatedLine: ({ annotation, ...props }) => (<InnerLine merge={props} data-focus={true} className="" />),}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 elementsconst containerRect = ref.current.getBoundingClientRect()let top = Infinitylet bottom = -InfinityfocusedElements.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 visibleif (bottom > containerRect.height || top < 0) {ref.current.scrollTo({top: ref.current.scrollTop + top - 10,behavior: firstRender.current ? "instant" : "smooth",})}firstRender.current = false}})}