diff --git a/package-lock.json b/package-lock.json index 906058a51..cbb379b81 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28238,9 +28238,9 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, "tslib": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.2.tgz", - "integrity": "sha512-wAH28hcEKwna96/UacuWaVspVLkg4x1aDM9JlzqaQTOFczCktkVAb5fmXChgandR1EraDPs2w8P+ozM+oafwxg==" + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.3.tgz", + "integrity": "sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ==" } } }, diff --git a/package.json b/package.json index 472211c80..ab5cca477 100644 --- a/package.json +++ b/package.json @@ -52,6 +52,7 @@ "react-shadow": "^18.4.2", "react-simple-code-editor": "^0.11.0", "react-typist": "^2.0.5", + "react-use": "^15.3.4", "snyk": "^1.401.0", "use-dark-mode": "^2.3.1", "use-media": "^1.4.0", diff --git a/src/components/Terminal/Shell.js b/src/components/Terminal/Shell.js index f2ee43810..aec608b25 100644 --- a/src/components/Terminal/Shell.js +++ b/src/components/Terminal/Shell.js @@ -1,31 +1,43 @@ -import React, { useState, useRef, useLayoutEffect } from 'react'; +import React, { + forwardRef, + useState, + useRef, + useLayoutEffect, + useImperativeHandle, +} from 'react'; import PropTypes from 'prop-types'; import { css } from '@emotion/core'; import Command from './Command'; import theme from './theme'; import rollupIntoCommands from './rollupIntoCommands'; -const Shell = ({ animate, highlight, code }) => { - const ref = useRef(); +const Shell = forwardRef(({ animate, highlight, code }, ref) => { + const shellRef = useRef(); const [animated, setAnimated] = useState(false); const [height, setHeight] = useState(null); - const [step, setStep] = useState(1); const { tokens, getTokenProps } = highlight; const commands = rollupIntoCommands(tokens, code); - const shownCommands = animated ? commands.slice(0, step) : commands; + const [shownCommands, setShownCommands] = useState(commands); + + useImperativeHandle(ref, () => ({ + startAnimation: () => { + setAnimated(true); + setShownCommands(commands.slice(0, 1)); + }, + })); useLayoutEffect(() => { - const { height } = ref.current.getBoundingClientRect(); + const { height } = shellRef.current.getBoundingClientRect(); setHeight(height); if (animate) { - setAnimated(true); + setShownCommands([]); } }, [animate]); return (
{ getTokenProps={getTokenProps} typingDelay={idx === 0 ? 2000 : 500} onDone={() => { - setStep((step) => step + 1); + setShownCommands((shownCommands) => + commands.slice(0, shownCommands.length) + ); }} /> ))}); -}; +}); Shell.propTypes = { animate: PropTypes.bool, diff --git a/src/components/Terminal/Terminal.js b/src/components/Terminal/Terminal.js index b14fd39fd..beb04d7c0 100644 --- a/src/components/Terminal/Terminal.js +++ b/src/components/Terminal/Terminal.js @@ -1,17 +1,31 @@ -import React from 'react'; +import React, { useEffect, useRef } from 'react'; import PropTypes from 'prop-types'; import { css } from '@emotion/core'; import { Button, useClipboard } from '@newrelic/gatsby-theme-newrelic'; import Highlight from 'prism-react-renderer'; import Prism from 'prismjs'; import Shell from './Shell'; +import { useIntersection } from 'react-use'; const Terminal = ({ animate, children }) => { + const ref = useRef(); + const shellRef = useRef(); const code = children.trim(); const [copied, copy] = useClipboard(); + const intersection = useIntersection(ref, { + root: null, + rootMargin: '0px 0px -33% 0px', + }); + + useEffect(() => { + if (animate && intersection?.isIntersecting) { + shellRef.current.startAnimation(); + } + }, [animate, intersection]); return (