import React, { useEffect, useRef } from 'react'; import './index.less'; export enum LineType { Input, Output, } export enum ColorMode { Light, Dark, } export interface Props { name?: string; prompt?: string; colorMode?: ColorMode; lineData: Array<{ type: LineType; value: string | React.ReactNode }>; startingInputValue?: string; } const Terminal = ({ name, prompt, colorMode, lineData, startingInputValue = '', }: Props) => { const lastLineRef = useRef(null); // An effect that handles scrolling into view the last line of terminal input or output const performScrolldown = useRef(false); useEffect(() => { if (performScrolldown.current) { // skip scrolldown when the component first loads setTimeout( () => lastLineRef?.current?.scrollIntoView({ behavior: 'smooth', block: 'nearest', }), 500, ); } performScrolldown.current = true; }, [lineData.length]); const renderedLineData = lineData.map((ld, i) => { const classes = ['react-terminal-line']; if (ld.type === LineType.Input) { classes.push('react-terminal-input'); } // `lastLineRef` is used to ensure the terminal scrolls into view to the last line; make sure to add the ref to the last if (lineData.length === i + 1) { return ( {ld.value} ); } else { return ( {ld.value} ); } }); const classes = ['react-terminal-wrapper']; if (colorMode === ColorMode.Light) { classes.push('react-terminal-light'); } return (
{renderedLineData}
); }; export default Terminal;