|
1 | 1 | "use client"
|
2 | 2 |
|
3 |
| -import { |
4 |
| - HighlightedCode, |
5 |
| - Pre, |
6 |
| - AnnotationHandler, |
7 |
| - InnerPre, |
8 |
| - getPreRef, |
9 |
| - InnerLine, |
10 |
| -} from "codehike/code" |
11 |
| -import React, { useLayoutEffect, useRef, useState } from "react" |
| 3 | +import { HighlightedCode, Pre } from "codehike/code" |
| 4 | +import React, { useState } from "react" |
| 5 | +import { focus } from "./focus" |
12 | 6 |
|
13 | 7 | const ranges = {
|
14 | 8 | lorem: { fromLineNumber: 1, toLineNumber: 5 },
|
@@ -42,67 +36,18 @@ export function CodeContainer({ code }: { code: HighlightedCode }) {
|
42 | 36 | <button
|
43 | 37 | onClick={() => setFocused("lorem")}
|
44 | 38 | disabled={focused === "lorem"}
|
45 |
| - className="border border-current rounded px-2 disabled:opacity-60" |
| 39 | + className="border border-current rounded px-2" |
46 | 40 | >
|
47 | 41 | focus `lorem`
|
48 | 42 | </button>{" "}
|
49 | 43 | <button
|
50 | 44 | onClick={() => setFocused("dolor")}
|
51 | 45 | disabled={focused === "dolor"}
|
52 |
| - className="border border-current rounded px-2 disabled:opacity-60" |
| 46 | + className="border border-current rounded px-2" |
53 | 47 | >
|
54 | 48 | focus `dolor`
|
55 | 49 | </button>
|
56 | 50 | </div>
|
57 | 51 | </>
|
58 | 52 | )
|
59 | 53 | }
|
60 |
| - |
61 |
| -const focus: AnnotationHandler = { |
62 |
| - name: "focus", |
63 |
| - PreWithRef: (props) => { |
64 |
| - const ref = getPreRef(props) |
65 |
| - useScrollToFocus(ref) |
66 |
| - return <InnerPre merge={props} /> |
67 |
| - }, |
68 |
| - Line: (props) => ( |
69 |
| - <InnerLine |
70 |
| - merge={props} |
71 |
| - className="opacity-50 data-[focus]:opacity-100 px-2" |
72 |
| - /> |
73 |
| - ), |
74 |
| - AnnotatedLine: ({ annotation, ...props }) => ( |
75 |
| - <InnerLine merge={props} data-focus={true} className="bg-zinc-700/30" /> |
76 |
| - ), |
77 |
| -} |
78 |
| - |
79 |
| -function useScrollToFocus(ref: React.RefObject<HTMLPreElement>) { |
80 |
| - const firstRender = useRef(true) |
81 |
| - useLayoutEffect(() => { |
82 |
| - if (ref.current) { |
83 |
| - // find all descendants whith data-focus="true" |
84 |
| - const focusedElements = ref.current.querySelectorAll( |
85 |
| - "[data-focus=true]", |
86 |
| - ) as NodeListOf<HTMLElement> |
87 |
| - |
88 |
| - // find top and bottom of the focused elements |
89 |
| - const containerRect = ref.current.getBoundingClientRect() |
90 |
| - let top = Infinity |
91 |
| - let bottom = -Infinity |
92 |
| - focusedElements.forEach((el) => { |
93 |
| - const rect = el.getBoundingClientRect() |
94 |
| - top = Math.min(top, rect.top - containerRect.top) |
95 |
| - bottom = Math.max(bottom, rect.bottom - containerRect.top) |
96 |
| - }) |
97 |
| - |
98 |
| - // scroll to the focused elements if any part of them is not visible |
99 |
| - if (bottom > containerRect.height || top < 0) { |
100 |
| - ref.current.scrollTo({ |
101 |
| - top: ref.current.scrollTop + top - 10, |
102 |
| - behavior: firstRender.current ? "instant" : "smooth", |
103 |
| - }) |
104 |
| - } |
105 |
| - firstRender.current = false |
106 |
| - } |
107 |
| - }) |
108 |
| -} |
0 commit comments