WK 0d217e466f
refactor: optimization (#5362)
* chore(deps): bump RA versions

* chore(deps): bump RA versions

* chore(deps): bump RA versions

* chore: changeset

* chore(deps): remove unnecessary dependencies

* fix(calendar): typing issue

* refactor(system): remove unused SupportedCalendars

* refactor(system): move I18nProviderProps to type

* refactor: use `spectrumCalendarProps<DateValue>["createCalendar"]`

* feat: add consistent-type-imports

* fix: eslint

* chore: add changeset

* refactor: remove unused deps
2025-06-09 14:17:44 +08:00

99 lines
2.8 KiB
TypeScript

"use client";
// Inspired by https://github.dev/modulz/stitches-site code demo
import type {CodeBlockProps} from "./code-block";
import React from "react";
import rangeParser from "parse-numeric-range";
import CodeBlock from "./code-block";
import {CopyButton} from "@/components";
export interface CodeWindowProps extends CodeBlockProps {
showCopy?: boolean;
}
export const CodeWindow: React.FC<CodeWindowProps> = ({highlightLines, showCopy, ...props}) => {
const wrapperRef = React.useRef<HTMLPreElement>(null);
React.useEffect(() => {
const pre = wrapperRef.current;
if (!pre) return;
const PADDING = 15;
let codeInner = pre.querySelector("code") ?? null;
const codeBlockHeight = pre.clientHeight - PADDING * 2;
const lines = pre.querySelectorAll<HTMLElement>(".highlight-line");
if (!highlightLines) {
lines.forEach((line) => {
line.classList.remove("off");
});
if (codeInner) {
codeInner.style.transform = `translate3d(0, 0, 0)`;
}
return;
}
const linesToHighlight = rangeParser(highlightLines);
const firstLineNumber = Math.max(0, linesToHighlight[0] - 1);
const lastLineNumber = Math.min(lines.length - 1, [...linesToHighlight].reverse()[0] - 1);
const firstLine = lines[firstLineNumber];
const lastLine = lines[lastLineNumber];
// Prevent errors in case the right line doesn't exist
if (!firstLine || !lastLine) {
// eslint-disable-next-line no-console
console.warn(`CodeWindow: Error finding the right line`);
return;
}
const linesHeight = lastLine.offsetTop - firstLine.offsetTop;
const maxDistance = (codeInner?.clientHeight || 0) - codeBlockHeight;
const codeFits = linesHeight < codeBlockHeight;
const lastLineIsBelow = lastLine.offsetTop > codeBlockHeight - PADDING;
const lastLineIsAbove = !lastLineIsBelow;
let translateY = 0;
if (codeFits && lastLineIsAbove) {
translateY = 0;
} else if (codeFits && lastLineIsBelow) {
const dist = firstLine.offsetTop - (codeBlockHeight - linesHeight) / 2;
translateY = dist > maxDistance ? maxDistance : dist;
} else {
translateY = firstLine.offsetTop;
}
lines.forEach((line, i) => {
const lineIndex = i + 1;
if (linesToHighlight.includes(lineIndex)) {
line.setAttribute("data-highlighted", "true");
} else {
line.setAttribute("data-highlighted", "false");
}
});
requestAnimationFrame(
() => codeInner && (codeInner.style.transform = `translate3d(0, ${-translateY}px, 0)`),
);
}, [highlightLines]);
return (
<div className="relative">
<CodeBlock ref={wrapperRef} {...props} />
{showCopy && <CopyButton className="top-2 absolute right-2" value={props.value} />}
</div>
);
};