automagically scroll to the selected line on load
This commit is contained in:
@@ -5,7 +5,7 @@ import EditorPrismStyle from './EditorPrismStyle';
|
|||||||
import { getHighlighter } from '../util/highlighting';
|
import { getHighlighter } from '../util/highlighting';
|
||||||
|
|
||||||
export default function EditorTextArea({ code, setCode, language, fontSize }) {
|
export default function EditorTextArea({ code, setCode, language, fontSize }) {
|
||||||
const [isSelected, toggleSelected] = useSelectedLine();
|
const [isSelected, isSelectionMiddle, toggleSelected] = useSelectedLine();
|
||||||
const highlight = getHighlighter(language);
|
const highlight = getHighlighter(language);
|
||||||
|
|
||||||
function highlightWithLineNumbers(input, grammar) {
|
function highlightWithLineNumbers(input, grammar) {
|
||||||
@@ -16,6 +16,7 @@ export default function EditorTextArea({ code, setCode, language, fontSize }) {
|
|||||||
<LineNumber
|
<LineNumber
|
||||||
lineNo={i + 1}
|
lineNo={i + 1}
|
||||||
selected={isSelected(i + 1)}
|
selected={isSelected(i + 1)}
|
||||||
|
shouldScroll={isSelectionMiddle(i + 1)}
|
||||||
toggleSelected={toggleSelected}
|
toggleSelected={toggleSelected}
|
||||||
/>
|
/>
|
||||||
<span dangerouslySetInnerHTML={{ __html: line }} />
|
<span dangerouslySetInnerHTML={{ __html: line }} />
|
||||||
@@ -54,15 +55,21 @@ export default function EditorTextArea({ code, setCode, language, fontSize }) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const LineNumber = ({ lineNo, selected, toggleSelected }) => {
|
const LineNumber = ({ lineNo, selected, shouldScroll, toggleSelected }) => {
|
||||||
|
const autoScroll = useAutoScroll(shouldScroll);
|
||||||
|
|
||||||
function click(e) {
|
function click(e) {
|
||||||
toggleSelected(lineNo, e.shiftKey);
|
toggleSelected(lineNo, e.shiftKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
return selected ? (
|
return selected ? (
|
||||||
<HighlightedLineNumber onClick={click}>{lineNo}</HighlightedLineNumber>
|
<HighlightedLineNumber ref={autoScroll} onClick={click}>
|
||||||
|
{lineNo}
|
||||||
|
</HighlightedLineNumber>
|
||||||
) : (
|
) : (
|
||||||
<PlainLineNumber onClick={click}>{lineNo}</PlainLineNumber>
|
<PlainLineNumber ref={autoScroll} onClick={click}>
|
||||||
|
{lineNo}
|
||||||
|
</PlainLineNumber>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -150,7 +157,40 @@ function useSelectedLine() {
|
|||||||
return lineNo >= Math.min(...selected) && lineNo <= Math.max(...selected);
|
return lineNo >= Math.min(...selected) && lineNo <= Math.max(...selected);
|
||||||
}
|
}
|
||||||
|
|
||||||
return [isSelected, toggleSelected];
|
// is a line in the middle of the selection
|
||||||
|
function isSelectionMiddle(lineNo) {
|
||||||
|
if (selected[0] === -1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (selected[1] === -1) {
|
||||||
|
return selected[0] === lineNo;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
lineNo === Math.floor((Math.min(...selected) + Math.max(...selected)) / 2)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return [isSelected, isSelectionMiddle, toggleSelected];
|
||||||
|
}
|
||||||
|
|
||||||
|
function useAutoScroll(shouldScroll) {
|
||||||
|
const [firstRender, setFirstRender] = useState(true);
|
||||||
|
const ref = useRef(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// only attempt to autoscroll if this is the first render.
|
||||||
|
if (!firstRender) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setFirstRender(false);
|
||||||
|
|
||||||
|
if (shouldScroll) {
|
||||||
|
ref.current.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
||||||
|
}
|
||||||
|
}, [shouldScroll, firstRender]);
|
||||||
|
|
||||||
|
return ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
const KEYCODE_ENTER = 13;
|
const KEYCODE_ENTER = 13;
|
||||||
|
|||||||
Reference in New Issue
Block a user