UNPKG

code-surfer

Version:
385 lines (330 loc) 10.2 kB
import React from 'react'; import { useSteps as useSteps$1, useDeck, Notes } from 'mdx-deck'; import { UnknownError, CodeSurfer } from '@code-surfer/standalone'; import { parse } from 'shell-quote'; import { useSpring } from 'use-spring'; import { StylesProvider, Styled } from '@code-surfer/themes'; function Step() { return null; } function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; } /** * The metastring is the thing that comes after the language in markdown codeblocks * * ```js this is the metastring * code goes here * ``` */ function parseMetastring(metastring) { if (!metastring) { return {}; } var argv = parse(metastring); var result = {}; argv.forEach(function (arg) { if (!arg.includes("=")) { if (arg === "showNumbers") { result["showNumbers"] = true; } else { result.focus = arg; } } else { var _arg$split = arg.split(/=(.*)/), key = _arg$split[0], value = _arg$split[1]; if (value === "true") { result[key] = true; } else { result[key] = value; } } }); return result; } function isCode(element) { return element && element.props && element.props.mdxType === "pre"; } function readStepFromElement(element) { if (!isCode(element)) { throw new Error("Invalid element inside <CodeSurfer/>. Make sure to add empty lines (no spaces) before and after each codeblock."); } var props = element.props.children.props; var className = props.className && props.className.split(" ")[0]; return _extends({ code: props.children, lang: className && className.substring("language-".length) }, parseMetastring(props.metastring)); } var ErrorBoundary = /*#__PURE__*/ function (_React$Component) { _inheritsLoose(ErrorBoundary, _React$Component); function ErrorBoundary(props) { var _this; _this = _React$Component.call(this, props) || this; _this.state = {}; return _this; } ErrorBoundary.getDerivedStateFromError = function getDerivedStateFromError(error) { return { error: error }; }; var _proto = ErrorBoundary.prototype; _proto.componentDidCatch = function componentDidCatch(error, info) {// console.log(error, info); }; _proto.render = function render() { if (!this.state.error) { return this.props.children; } else if (this.state.error.element) { return this.state.error.element; } else { console.error(this.state.error); return React.createElement(UnknownError, { error: this.state.error }); } }; return ErrorBoundary; }(React.Component); function useSteps (stepsCount) { var step = useSteps$1(stepsCount); return step === Infinity ? 0 : step; } function useStepSpring(stepsCount) { // step index according to mdx-deck var targetStepIndex = useSteps(stepsCount - 1); // real number between 0 and stepsCount - 1 var _useSpring = useSpring(targetStepIndex, { decimals: 3, stiffness: 80, damping: 48, mass: 8 }), currentStepSpring = _useSpring[0]; return currentStepSpring; } function CodeSurferLayout(_ref) { var children = _ref.children, theme = _ref.theme; var deck = useDeck(); var steps = React.useMemo(getStepsFromChildren(children), [deck.index]); // useNotes(steps.map(s => s.notesElement)); var progress = useStepSpring(steps.length); return React.createElement("div", { style: { width: "100vw", maxWidth: "100%", height: "100vh", display: "flex", flexDirection: "column", justifyContent: "center", alignItems: "center" }, className: "cs-layout" }, React.createElement(CodeSurfer, { steps: steps, progress: progress, theme: theme })); } var getStepsFromChildren = function getStepsFromChildren(children) { return function () { var steps = React.Children.map(children || [], function (child) { return readStepFromElement(child); }).filter(function (x) { return x; }); if (steps.length === 0) { throw Error("No codeblocks found inside <CodeSurfer/>."); } return steps; }; }; var layout = (function (props) { return React.createElement(ErrorBoundary, null, React.createElement(CodeSurferLayout, Object.assign({}, props))); }); function useNotes(notesElements) { var context = useDeck(); React.useEffect(function () { if (!context || !context.register) return; if (typeof context.index === "undefined") return; var notes = getNotesFromElements(notesElements); context.register(context.index, { notes: notes }); }, []); } function getNotesFromElements(notesElements) { var notes = notesElements.map(function (element) { if (!element) { // this is a step with empty notes return null; } var props = element.props; if (props.inline) { // this is <Notes inline={true} /> return { inline: true, text: props.children }; } // this is <Notes>something</Notes> // we shouldn't return an object here, // to be compatible with the default Presenter return props && props.children; }); if (notes.length) { var lastNotes = notes[notes.length - 1]; // we add an extra EOL to the last step notes[notes.length - 1] = (lastNotes || "") + "\n"; } return notes; } function ColumnLayout(_ref) { var children = _ref.children, _ref$themes = _ref.themes, themes = _ref$themes === void 0 ? [] : _ref$themes, sizes = _ref.sizes; var deck = useDeck(); var _React$useMemo = React.useMemo(function () { return getColumnsFromChildren(children, sizes); }, [deck.index]), columns = _React$useMemo[0], titles = _React$useMemo[1], subtitles = _React$useMemo[2], notesElements = _React$useMemo[3]; useNotes(notesElements); var progress = useStepSpring(columns[0].steps.length); var stepIndex = Math.round(progress); return React.createElement("div", { style: { width: "100vw", maxWidth: "100%", height: "100vh", display: "flex", flexDirection: "row", justifyContent: "center", alignItems: "center", fontSize: "0.8em", position: "relative" }, className: "cs-col-layout" }, columns.map(function (column, i) { return React.createElement(Column, { key: i, column: column, progress: progress, theme: themes[i] }); }), React.createElement(StylesProvider, null, React.createElement(Title, { text: titles[stepIndex] }), React.createElement(Subtitle, { text: subtitles[stepIndex] }))); } function Column(_ref2) { var column = _ref2.column, progress = _ref2.progress, theme = _ref2.theme; return React.createElement("div", { style: { flex: column.flex, overflow: "hidden", height: "100%" } }, column.isCode ? React.createElement(CodeSurfer, { steps: column.steps, progress: progress, theme: theme }) : React.createElement("div", { style: { display: "flex", justifyContent: "center", alignItems: "center", height: "100%" } }, column.steps[Math.round(progress)].element)); } function Title(_ref3) { var text = _ref3.text; if (!text) return null; return React.createElement(Styled.Title, { className: "cs-title" }, React.createElement("span", null, text)); } function Subtitle(_ref4) { var text = _ref4.text; if (!text) return null; return React.createElement(Styled.Subtitle, { className: "cs-subtitle", style: { margin: "0.3em 0" } }, React.createElement("span", null, text)); } function getColumnsFromChildren(children, sizes) { if (sizes === void 0) { sizes = []; } var columns = []; var stepElements = React.Children.toArray(children); if (stepElements.length === 0) { throw Error("No <Step/> found inside <CodeSurferColumns/>."); } stepElements.forEach(function (stepElement, stepIndex) { React.Children.toArray(stepElement.props.children).forEach(function (cellElement, columnIndex) { if (!cellElement || !cellElement.props) { throw Error("Invalid element inside <Step/>. Make sure to add empty lines (no spaces) before and after each element."); } columns[columnIndex] = columns[columnIndex] || { steps: [], isCode: true }; var step = isCode(cellElement) ? readStepFromElement(cellElement) : { element: cellElement }; columns[columnIndex].steps[stepIndex] = step; columns[columnIndex].isCode = columns[columnIndex].isCode && isCode(cellElement); }); }); if (columns.length === 0) { throw Error("<Step/> shouldn't be empty."); } columns.forEach(function (column, columnIndex) { column.flex = sizes[columnIndex] || 1; }); var titles = stepElements.map(function (stepElement) { return stepElement.props.title; }); var subtitles = stepElements.map(function (stepElement) { return stepElement.props.subtitle; }); var notesElements = stepElements.map(function (stepElement) { var stepChildren = React.Children.toArray(stepElement.props.children); var notesElement = stepChildren.find(function (element) { return element.props && element.props.originalType === Notes; }); return notesElement; }); return [columns, titles, subtitles, notesElements]; } var columnLayout = (function (props) { return React.createElement(ErrorBoundary, null, React.createElement(ColumnLayout, Object.assign({}, props))); }); export { layout as CodeSurfer, columnLayout as CodeSurferColumns, Step }; //# sourceMappingURL=code-surfer.esm.js.map