UNPKG

code-surfer

Version:
1,987 lines (1,765 loc) 62.1 kB
import React from 'react'; import { applyPatch, diffLines } from 'diff'; import Prism from 'prismjs'; import flat from 'array.prototype.flat'; import { useThemeUI, jsx, ThemeProvider } from 'theme-ui'; import 'prismjs/components/prism-markup'; import 'prismjs/components/prism-bash'; import 'prismjs/components/prism-clike'; import 'prismjs/components/prism-c'; import 'prismjs/components/prism-cpp'; import 'prismjs/components/prism-css'; import 'prismjs/components/prism-css-extras'; import 'prismjs/components/prism-javascript'; import 'prismjs/components/prism-jsx'; import 'prismjs/components/prism-js-extras'; import 'prismjs/components/prism-coffeescript'; import 'prismjs/components/prism-diff'; import 'prismjs/components/prism-git'; import 'prismjs/components/prism-go'; import 'prismjs/components/prism-graphql'; import 'prismjs/components/prism-json'; import 'prismjs/components/prism-less'; import 'prismjs/components/prism-makefile'; import 'prismjs/components/prism-markdown'; import 'prismjs/components/prism-objectivec'; import 'prismjs/components/prism-ocaml'; import 'prismjs/components/prism-python'; import 'prismjs/components/prism-reason'; import 'prismjs/components/prism-sass'; import 'prismjs/components/prism-scss'; import 'prismjs/components/prism-sql'; import 'prismjs/components/prism-stylus'; import 'prismjs/components/prism-typescript'; import 'prismjs/components/prism-wasm'; import 'prismjs/components/prism-yaml'; 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; } function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; } function grammarNotFound(_ref2) { var lang = _ref2.lang; return { element: React.createElement(ErrorBox, { header: "Oops, there's a problem", body: React.createElement(React.Fragment, null, "Syntax highlighter for ", React.createElement(Mark, null, "\"", lang, "\""), " not found.", React.createElement("p", null, "You can try importing it from prismjs with: ", React.createElement("br", null), React.createElement(Mark, null, "import \"prismjs/components/prism-", lang, "\"")), "(See", " ", React.createElement("a", { href: "https://prismjs.com/#supported-languages", style: { color: "grey" } }, "all the supported languages"), ")") }) }; } function invalidFocusNumber(n) { return { withFocusString: function withFocusString(focusString) { return { withStepIndex: function withStepIndex(stepIndex) { return { element: React.createElement(ErrorBox, { header: React.createElement(StepErrorHeader, { stepIndex: stepIndex }), body: React.createElement(React.Fragment, null, React.createElement(Mark, null, "\"", n, "\""), " isn't a valid number", " ", n != focusString && React.createElement(Mark, null, " (in \"", focusString, "\")")) }) }; } }; } }; } function invalidLineOrColumnNumber() { return { withFocusString: function withFocusString(focusString) { return { withStepIndex: function withStepIndex(stepIndex) { return { element: React.createElement(ErrorBox, { header: React.createElement(StepErrorHeader, { stepIndex: stepIndex }), body: React.createElement(React.Fragment, null, "Are you using \"0\" as a line or column number", " ", React.createElement(Mark, null, "in \"", focusString, "\""), "?", React.createElement("br", null), "(Line and column numbers should start at 1, not 0) ", React.createElement("br", null)) }) }; } }; } }; } function ErrorBox(_ref3) { var header = _ref3.header, body = _ref3.body; return React.createElement("div", { style: { background: "#290000", color: "#b96f70", border: "2px solid #b96f70", padding: "10px 30px", maxWidth: "90vw", margin: "0 auto", fontFamily: "monospace", fontSize: "1rem" } }, React.createElement("h3", null, header), React.createElement("p", null, body)); } function StepErrorHeader(_ref4) { var stepIndex = _ref4.stepIndex; return React.createElement(React.Fragment, null, "Oops, there's a problem with the", " ", React.createElement(Mark, null, stepIndex + 1, React.createElement("sup", null, ordinal(stepIndex + 1)), " step")); } function Mark(_ref5) { var children = _ref5.children; return React.createElement("mark", { style: { background: "none", color: "pink", fontWeight: "bolder" } }, children); } function ordinal(i) { var j = i % 10, k = i % 100; if (j == 1 && k != 11) { return "st"; } if (j == 2 && k != 12) { return "nd"; } if (j == 3 && k != 13) { return "rd"; } return "th"; } var newlineRe = /\r\n|\r|\n/; // Take a list of nested tokens // (token.content may contain an array of tokens) // and flatten it so content is always a string // and type the type of the leaf function flattenTokens(tokens) { var flatList = []; tokens.forEach(function (token) { var type = token.type, content = token.content; if (Array.isArray(content)) { flatList.push.apply(flatList, flattenTokens(content)); } else { flatList.push({ type: type, content: content }); } }); return flatList; } function wrapToken(prismToken, parentType) { if (parentType === void 0) { parentType = "plain"; } if (typeof prismToken === "string") { return { type: parentType, content: prismToken }; } if (Array.isArray(prismToken.content)) { return { type: prismToken.type, content: tokenizeStrings(prismToken.content, prismToken.type) }; } return wrapToken(prismToken.content, prismToken.type); } // Wrap strings in tokens function tokenizeStrings(prismTokens, parentType) { if (parentType === void 0) { parentType = "plain"; } return prismTokens.map(function (prismToken) { return wrapToken(prismToken, parentType); }); } function tokenize(code, language) { if (language === void 0) { language = "javascript"; } var grammar = Prism.languages[language]; if (!grammar) { throw grammarNotFound({ lang: language }); } var prismTokens = Prism.tokenize(code, Prism.languages[language]); var nestedTokens = tokenizeStrings(prismTokens); var tokens = flattenTokens(nestedTokens); var currentLine = []; var lines = [currentLine]; tokens.forEach(function (token) { var contentLines = token.content.split(newlineRe); var firstContent = contentLines.shift(); if (firstContent !== undefined && firstContent !== "") { currentLine.push({ type: token.type, content: firstContent }); } contentLines.forEach(function (content) { currentLine = []; lines.push(currentLine); if (content !== "") { currentLine.push({ type: token.type, content: content }); } }); }); return lines; } var newlineRe$1 = /\r\n|\r|\n/; function myDiff(oldCode, newCode) { var changes = diffLines(oldCode || "", newCode); var oldIndex = -1; return changes.map(function (_ref) { var value = _ref.value, count = _ref.count, removed = _ref.removed, added = _ref.added; var lines = value.split(newlineRe$1); // check if last line is empty, if it is, remove it var lastLine = lines.pop(); if (lastLine) { lines.push(lastLine); } var result = { oldIndex: oldIndex, lines: lines, count: count, removed: removed, added: added }; if (!added) { oldIndex += count || 0; } return result; }); } function insert(array, index, elements) { return array.splice.apply(array, [index, 0].concat(elements)); } function slideDiff(lines, codes, slideIndex, language) { var prevLines = lines.filter(function (l) { return l.slides.includes(slideIndex - 1); }); var prevCode = codes[slideIndex - 1] || ""; var currCode = codes[slideIndex]; var changes = myDiff(prevCode, currCode); changes.forEach(function (change) { if (change.added) { var prevLine = prevLines[change.oldIndex]; var addAtIndex = lines.indexOf(prevLine) + 1; var addLines = change.lines.map(function (content) { return { content: content, slides: [slideIndex], tokens: [] }; }); insert(lines, addAtIndex, addLines); } else if (!change.removed) { for (var j = 1; j <= (change.count || 0); j++) { prevLines[change.oldIndex + j].slides.push(slideIndex); } } }); var tokenLines = tokenize(currCode, language); var currLines = lines.filter(function (l) { return l.slides.includes(slideIndex); }); currLines.forEach(function (line, index) { return line.tokens = tokenLines[index]; }); } function parseLines(codes, language) { var lines = []; for (var slideIndex = 0; slideIndex < codes.length; slideIndex++) { slideDiff(lines, codes, slideIndex, language); } return lines; } function getSlides(codes, language) { // codes are in reverse cronological order var lines = parseLines(codes, language); // console.log("lines", lines); return codes.map(function (_, slideIndex) { return lines.map(function (line, lineIndex) { return { content: line.content, tokens: line.tokens, isNew: !line.slides.includes(slideIndex + 1), show: line.slides.includes(slideIndex), key: lineIndex }; }).filter(function (line) { return line.show; }); }); } function getCodes(rawSteps) { var codes = []; rawSteps.forEach(function (s, i) { if (s.lang === "diff" && i > 0) { codes[i] = applyPatch(codes[i - 1], s.code); } else { codes[i] = s.code; } }); return codes; } function parseFocus(focus) { if (!focus) { throw new Error("Focus cannot be empty"); } try { var parts = focus.split(/,(?![^\[]*\])/g).map(parsePart); return new Map(flat(parts)); } catch (error) { if (error.withFocusString) { throw error.withFocusString(focus); } else { throw error; } } } function parsePart(part) { // a part could be // - a line number: "2" // - a line range: "5:9" // - a line number with a column selector: "2[1,3:5,9]" var columnsMatch = part.match(/(\d+)\[(.+)\]/); if (columnsMatch) { var line = columnsMatch[1], columns = columnsMatch[2]; var columnsList = columns.split(",").map(expandString); var lineIndex = Number(line) - 1; var columnIndexes = flat(columnsList).map(function (c) { return c - 1; }); return [[lineIndex, columnIndexes]]; } else { return expandString(part).map(function (lineNumber) { return [lineNumber - 1, true]; }); } } function expandString(part) { // Transforms something like // - "1:3" to [1,2,3] // - "4" to [4] var _part$split = part.split(":"), start = _part$split[0], end = _part$split[1]; // todo check if start is 0, line numbers and column numbers start at 1 if (!isNaturalNumber(start)) { throw invalidFocusNumber(start); } var startNumber = Number(start); if (startNumber < 1) { throw invalidLineOrColumnNumber(); } if (!end) { return [startNumber]; } else { if (!isNaturalNumber(end)) { throw invalidFocusNumber(end); } var list = []; for (var i = startNumber; i <= +end; i++) { list.push(i); } return list; } } function isNaturalNumber(n) { n = n.toString(); // force the value in case it is not var n1 = Math.abs(n), n2 = parseInt(n, 10); return !isNaN(n1) && n2 === n1 && n1.toString() === n; } function parseSteps(rawSteps, lang) { var codes = getCodes(rawSteps); var stepsLines = getSlides(codes.reverse(), lang).reverse(); var steps = rawSteps.map(function (step, i) { var lines = stepsLines[i]; try { return parseStep(step, lines); } catch (e) { if (e.withStepIndex) { throw e.withStepIndex(i); } else { throw e; } } }); steps.forEach(function (step) { var lines = step.lines, focusMap = step.focusMap; lines.forEach(function (line, index) { line.focus = focusMap.has(index); var columnFocus = focusMap.get(index); line.focusPerToken = Array.isArray(columnFocus); if (Array.isArray(columnFocus)) { // this mutates the tokens array in order to change it to the same line in other steps splitTokensToColumns(line.tokens); line.tokens = setTokenFocus(line.tokens, columnFocus); } }); }); return steps; } function parseStep(step, lines) { var focus = step.focus, rest = _objectWithoutPropertiesLoose(step, ["focus"]); var focusMap = focus ? parseFocus(focus) : getDefaultFocus(lines); var focusIndexes = Array.from(focusMap.keys()); var focusStart = Math.min.apply(Math, focusIndexes); var focusEnd = Math.max.apply(Math, focusIndexes); return _extends({ lines: lines, focusMap: focusMap, focusStart: focusStart, focusEnd: focusEnd, focusCenter: (focusStart + focusEnd + 1) / 2, focusCount: focusEnd - focusStart + 1 }, rest); } function getDefaultFocus(lines) { var indexes = lines.map(function (line, index) { return line.isNew ? index : -1; }).filter(function (index) { return index !== -1; }); return new Map(indexes.map(function (i) { return [i, true]; })); } function splitTokensToColumns(tokenArray) { var tokens = Array.from(tokenArray); var key = 0; tokenArray.splice(0, tokenArray.length); tokens.forEach(function (token) { var chars = Array.from(token.content); chars.forEach(function (_char) { return tokenArray.push(_extends({}, token, { content: _char, key: key++ })); }); }); } function setTokenFocus(tokens, focusColumns) { // Assumes that tokens are already splitted in columns // Return new token objects to avoid changing other steps tokens return tokens.map(function (token, i) { return _extends({}, token, { focus: focusColumns.includes(i) }); }); } var Tuple = /*#__PURE__*/ function () { function Tuple(prev, next) { this.prev = prev; this.next = next; } var _proto = Tuple.prototype; _proto.spread = function spread() { var prev = this.prev; var next = this.next; return [prev, next]; }; _proto.select = function select(selector) { var _this$spread = this.spread(), prev = _this$spread[0], next = _this$spread[1]; var newPrev = prev === null ? null : prev === undefined ? undefined : selector(prev), newNext = next === null ? null : next === undefined ? undefined : selector(next); return new Tuple(newPrev, newNext); }; _proto.selectMany = function selectMany(selector) { var _this$spread2 = this.spread(), prev = _this$spread2[0], next = _this$spread2[1]; var newPrev = prev === null ? null : prev === undefined ? undefined : selector(prev), newNext = next === null ? null : next === undefined ? undefined : selector(next); return new ArrayTuple(newPrev, newNext); }; _proto.get = function get(_key) { throw Error("Get only supported in ArrayTuple"); }; _proto.map = function map(_mapper) { throw Error("Map only supported in ArrayTuple"); }; return Tuple; }(); var ArrayTuple = /*#__PURE__*/ function (_Tuple) { _inheritsLoose(ArrayTuple, _Tuple); function ArrayTuple() { return _Tuple.apply(this, arguments) || this; } var _proto2 = ArrayTuple.prototype; _proto2._getChildrenMap = function _getChildrenMap() { if (!this._dict) { var _this$spread3 = this.spread(), maybePrevs = _this$spread3[0], maybeNexts = _this$spread3[1]; var prevs = maybePrevs || []; var nexts = maybeNexts || []; var unsortedMap = new Map(prevs.map(function (prev) { return [prev.key, { prev: prev }]; })); nexts.forEach(function (next) { var _ref = unsortedMap.get(next.key) || { prev: undefined }, prev = _ref.prev; unsortedMap.set(next.key, { prev: prev, next: next }); }); var sortedKeys = Array.from(unsortedMap.keys()); sortedKeys.sort(function (a, b) { return a < b ? -1 : a > b ? 1 : 0; }); this._dict = new Map(sortedKeys.map(function (key) { var _ref2 = unsortedMap.get(key) || {}, _ref2$prev = _ref2.prev, prev = _ref2$prev === void 0 ? undefined : _ref2$prev, _ref2$next = _ref2.next, next = _ref2$next === void 0 ? undefined : _ref2$next; return [key, new Tuple(prev, next)]; })); } return this._dict; }; _proto2.get = function get(key) { var childrenMap = this._getChildrenMap(); return childrenMap.get(key); }; _proto2.map = function map(mapper) { var _this = this; var childrenMap = this._getChildrenMap(); var result = []; childrenMap.forEach(function (tuple, key) { return result.push(mapper(tuple, key, _this)); }); return result; }; return ArrayTuple; }(Tuple); var Context = /*#__PURE__*/ function () { function Context(tuple, t, parent) { this.tuple = tuple; this.t = t; this.parent = parent; } var _proto = Context.prototype; _proto.useSelect = function useSelect(selector) { var _this = this; var newTuple = React.useMemo(function () { return _this.tuple.select(selector); }, [this.tuple]); return new Context(newTuple, this.t); }; _proto.useSelectMany = function useSelectMany(selector) { var _this2 = this; var newTuple = React.useMemo(function () { return _this2.tuple.selectMany(selector); }, [this.tuple]); return new ListContext(newTuple, this.t); }; _proto.spread = function spread() { return this.tuple.spread(); }; _proto.animate = function animate(animation, config) { if (config === void 0) { config = {}; } var _this$tuple$spread = this.tuple.spread(), prev = _this$tuple$spread[0], next = _this$tuple$spread[1]; if (config.when && !config.when(prev, next)) { return {}; } var staggeredT = this.t; if (config.stagger) { if (!this.parent) { throw Error("Can't use stagger without a parent context"); } var items = this.parent.map(function (childCtx) { var _childCtx$spread = childCtx.spread(), prevChild = _childCtx$spread[0], nextChild = _childCtx$spread[1]; return { isSelected: !config.when || config.when(prevChild, nextChild), isThisChild: prevChild === prev && nextChild === next }; }).filter(function (x) { return x.isSelected; }); var N = items.length; if (N > 1) { var currentIndex = items.findIndex(function (x) { return x.isThisChild; }); var duration = 1 - config.stagger; var tick = config.stagger / (N - 1); staggeredT = Math.min(1, Math.max(0, (this.t - currentIndex * tick) / duration)); } } return animation(prev, next, staggeredT); }; _proto.animations = function animations(_animations) { var _this3 = this; var results = _animations.map(function (_ref) { var animation = _ref.animation, config = _objectWithoutPropertiesLoose(_ref, ["animation"]); return _this3.animate(animation, config); }); return merge(results); }; return Context; }(); var ListContext = /*#__PURE__*/ function (_Context) { _inheritsLoose(ListContext, _Context); function ListContext(tuple, t) { var _this4; _this4 = _Context.call(this, tuple, t) || this; _this4.tuple = tuple; return _this4; } var _proto2 = ListContext.prototype; _proto2.map = function map(mapper) { var _this5 = this; return this.tuple.map(function (childTuple, key) { return mapper(new Context(childTuple, _this5.t, _this5), key); }); }; return ListContext; }(Context); function useAnimationContext(items, playhead) { var prev = items[Math.floor(playhead)]; var next = items[Math.floor(playhead) + 1]; var tuple = React.useMemo(function () { return new Tuple(prev, next); }, [prev, next]); return new Context(tuple, playhead % 1); } var MULTIPLY = "multiply"; function merge(results, composite) { if (composite === void 0) { composite = MULTIPLY; } var firstResult = results[0]; if (results.length < 2) { return firstResult; } if (Array.isArray(firstResult)) { return mergeArrays(results, composite); } else { return mergeObjects(results, composite); } } function mergeObjects(results, composite) { var merged = Object.assign.apply(Object, [{}].concat(results)); if (composite === MULTIPLY) { var opacities = results.map(function (x) { return x.opacity; }).filter(function (x) { return x != null; }); if (opacities.length !== 0) { merged.opacity = opacities.reduce(function (a, b) { return a * b; }); } } return merged; } function mergeArrays(results, composite) { var firstResult = results[0]; return firstResult.map(function (_, i) { return merge(results.map(function (result) { return result[i]; }), composite); }); } var easing = { // no easing, no acceleration linear: function linear(t) { return t; }, // accelerating from zero velocity easeInQuad: function easeInQuad(t) { return t * t; }, // decelerating to zero velocity easeOutQuad: function easeOutQuad(t) { return t * (2 - t); }, // acceleration until halfway, then deceleration easeInOutQuad: function easeInOutQuad(t) { return t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t; }, // accelerating from zero velocity easeInCubic: function easeInCubic(t) { return t * t * t; }, // decelerating to zero velocity easeOutCubic: function easeOutCubic(t) { return --t * t * t + 1; }, // acceleration until halfway, then deceleration easeInOutCubic: function easeInOutCubic(t) { return t < 0.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1; }, // accelerating from zero velocity easeInQuart: function easeInQuart(t) { return t * t * t * t; }, // decelerating to zero velocity easeOutQuart: function easeOutQuart(t) { return 1 - --t * t * t * t; }, // acceleration until halfway, then deceleration easeInOutQuart: function easeInOutQuart(t) { return t < 0.5 ? 8 * t * t * t * t : 1 - 8 * --t * t * t * t; }, // accelerating from zero velocity easeInQuint: function easeInQuint(t) { return t * t * t * t * t; }, // decelerating to zero velocity easeOutQuint: function easeOutQuint(t) { return 1 + --t * t * t * t * t; }, // acceleration until halfway, then deceleration easeInOutQuint: function easeInOutQuint(t) { return t < 0.5 ? 16 * t * t * t * t * t : 1 + 16 * --t * t * t * t * t; } }; var MULTIPLY$1 = "multiply"; /* eslint-disable */ function mergeResults(results, composite) { if (composite === void 0) { composite = null; } var firstResult = results[0]; if (results.length < 2) { return firstResult; } if (Array.isArray(firstResult)) { return firstResult.map(function (_, i) { return mergeResults(results.map(function (result) { return result[i]; }), composite); }); } else { var merged = Object.assign.apply(Object, [{}].concat(results)); if (composite === MULTIPLY$1) { var opacities = results.map(function (x) { return x.opacity; }).filter(function (x) { return x != null; }); if (opacities.length !== 0) { merged.opacity = opacities.reduce(function (a, b) { return a * b; }); } } return merged; } } var playhead = { always: function always(props, context) { return function (t) { return props.value; }; }, step: function step(props, context) { return function (t) { var from = props.from, to = props.to; return t < 0.5 ? from : to; }; }, tween: function tween(props, context) { return function (t) { var from = props.from, to = props.to, _props$ease = props.ease, ease = _props$ease === void 0 ? easing.linear : _props$ease; var style = {}; Object.keys(from).forEach(function (key) { var value = from[key] + (to[key] - from[key]) * ease(t); if (key === "x") { style["transform"] = "translateX(" + value + "px)"; } else { style[key] = value; } }); return style; }; }, chain: function chain(_ref, ctx) { var fns = _ref.children, durations = _ref.durations; return function (t) { var style = run(fns[0], 0, ctx); var lowerDuration = 0; for (var i = 0; i < fns.length; i++) { var fn = fns[i]; var thisDuration = durations[i]; var upperDuration = lowerDuration + thisDuration; if (lowerDuration <= t && t <= upperDuration) { var innerT = (t - lowerDuration) / thisDuration; style = mergeResults([style, run(fn, innerT, ctx)]); } else if (upperDuration < t) { // merge the end of previous animation style = mergeResults([style, run(fn, 1, ctx)]); } else if (t < lowerDuration) { // merge the start of future animation style = mergeResults([run(fn, 0, ctx), style]); } lowerDuration = upperDuration; } return style; }; }, delay: function delay() { return function () { return {}; }; }, parallel: function parallel(_ref2, ctx) { var fns = _ref2.children; return function (t) { var styles = fns.map(function (fn) { return run(fn, t, ctx); }); var result = mergeResults(styles, MULTIPLY$1); return result; }; }, list: function list(_ref3, ctx) { var items = _ref3.forEach, children = _ref3.children; return function (t) { var mapper = children[0]; var results = items.map(mapper); return results.map(function (element) { return run(element, t, ctx); }); }; } }; function createAnimation(type, config) { for (var _len = arguments.length, children = new Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) { children[_key - 2] = arguments[_key]; } var props = _extends({}, config, { children: children }); return { type: typeof type === "string" ? playhead[type] : type, props: props }; } function Context$1() { throw Error("shouldnt run Context"); } function run(node, t, context) { if (context === void 0) { context = {}; } if (node.type === Context$1) { var _node$props = node.props, children = _node$props.children, patch = _objectWithoutPropertiesLoose(_node$props, ["children"]); var newContext = _extends({}, context, {}, patch); return run(children[0], t, newContext); } var result = node.type(node.props, context); if (result.type) { return run(result, t, context); } else { return result(t); } } /* @jsx createAnimation */ function FadeIn() { return createAnimation("tween", { from: { opacity: 0 }, to: { opacity: 1 } }); } function FadeOut() { return createAnimation("tween", { from: { opacity: 1 }, to: { opacity: 0 } }); } function FadeOutIn() { return createAnimation("chain", { durations: [0.5, 0.5] }, createAnimation(FadeOut, null), createAnimation(FadeIn, null)); } var dx = 250; var offOpacity = 0.3; var outOpacity = 0; var outHieght = 0; var lineDurations = [0.2, 0.6, 0.2]; var SlideToLeft = function SlideToLeft() { return createAnimation("chain", { durations: lineDurations }, createAnimation("tween", { from: { x: 0, opacity: 1 }, to: { x: -dx, opacity: outOpacity }, ease: easing.easeInQuad }), createAnimation("delay", null), createAnimation("delay", null)); }; var SlideFromRight = function SlideFromRight() { return createAnimation("chain", { durations: lineDurations }, createAnimation("delay", null), createAnimation("delay", null), createAnimation("tween", { from: { x: dx, opacity: outOpacity }, to: { x: 0, opacity: 1 }, ease: easing.easeOutQuad })); }; function ShrinkHeight(_ref) { var lineHeight = _ref.lineHeight; if (!lineHeight) { return createAnimation("step", { from: { height: null }, to: { height: 0 } }); } return createAnimation("tween", { from: { height: lineHeight }, to: { height: outHieght }, ease: easing.easeInOutQuad }); } function ExitLine(_ref2) { var lineHeight = _ref2.lineHeight; return createAnimation("chain", { durations: lineDurations }, createAnimation("delay", null), createAnimation(ShrinkHeight, { lineHeight: lineHeight })); } function GrowHeight(_ref3) { var lineHeight = _ref3.lineHeight; if (!lineHeight) { return createAnimation("step", { from: { height: 0 }, to: { height: null } }); } return createAnimation("tween", { from: { height: outHieght }, to: { height: lineHeight }, ease: easing.easeInOutQuad }); } function EnterLine(_ref4) { var lineHeight = _ref4.lineHeight; return createAnimation("chain", { durations: lineDurations }, createAnimation("delay", null), createAnimation(GrowHeight, { lineHeight: lineHeight }), createAnimation("delay", null)); } var fadeIn = function fadeIn(t) { return run(createAnimation(FadeIn, null), t); }; var fadeOut = function fadeOut(t) { return run(createAnimation(FadeOut, null), t); }; var fadeOutIn = function fadeOutIn(t) { return run(createAnimation(FadeOutIn, null), t); }; function switchText(prev, next, t) { // TODO merge with fadeBackground and fadeText if (t < 0.5) { return prev && prev.value; } else { return next && next.value; } } function any(prev, next) { return prev || next; } var exitLine = function exitLine(prev, next, t) { var dimensions = any(prev, next).dimensions; return run(createAnimation(ExitLine, { lineHeight: dimensions && dimensions.lineHeight }), t); }; var enterLine = function enterLine(prev, next, t) { var dimensions = any(prev, next).dimensions; return run(createAnimation(EnterLine, { lineHeight: dimensions && dimensions.lineHeight }), t); }; var slideToLeft = function slideToLeft(prev, next, t) { return run(createAnimation(SlideToLeft, null), t); }; var slideFromRight = function slideFromRight(prev, next, t) { return run(createAnimation(SlideFromRight, null), t); }; var focusLine = function focusLine(prev, next, t) { return run(createAnimation("tween", { from: { opacity: prev && prev.focus ? 1 : offOpacity }, to: { opacity: next && next.focus ? 1 : offOpacity } }), t); }; var focusToken = function focusToken(prev, next, t) { var from = prev && prev.focus === false ? offOpacity : 1; var to = next && next.focus === false ? offOpacity : 1; return run(createAnimation("tween", { from: { opacity: from }, to: { opacity: to } }), t); }; var scaleToFocus = function scaleToFocus(prev, next, t) { var dimensions = any(prev, next).dimensions; if (!dimensions) { return function (_) { return { scale: 1 }; }; } var prevZoom = getZoom(prev); var nextZoom = getZoom(next); return run(createAnimation("tween", { from: { scale: prevZoom || nextZoom }, to: { scale: nextZoom || prevZoom }, ease: easing.easeInOutQuad }), t); }; var scrollToFocus = function scrollToFocus(prevStep, nextStep, t) { var dimensions = any(prevStep, nextStep).dimensions; if (!dimensions) { return function (_) { return { scrollTop: 0 }; }; } var prevCenter = prevStep ? prevStep.focusCenter * dimensions.lineHeight : 0; var nextCenter = nextStep ? nextStep.focusCenter * dimensions.lineHeight : 0; return run(createAnimation("chain", { durations: lineDurations }, createAnimation("delay", null), createAnimation("tween", { from: { scrollTop: prevCenter }, to: { scrollTop: nextCenter }, ease: easing.easeInOutQuad }), createAnimation("delay", null)), t); }; function getZoom(step) { if (!step) return null; var _step$dimensions = step.dimensions, paddingBottom = _step$dimensions.paddingBottom, paddingTop = _step$dimensions.paddingTop, containerHeight = _step$dimensions.containerHeight, containerWidth = _step$dimensions.containerWidth, contentWidth = _step$dimensions.contentWidth, lineHeight = _step$dimensions.lineHeight; var contentHeight = step.focusCount * lineHeight; var availableHeight = containerHeight - Math.max(paddingBottom, paddingTop) * 2; var yZoom = availableHeight / contentHeight; // if there are lines that are too long for the container var xZoom = 0.9 * containerWidth / contentWidth; return Math.min(yZoom, 1, xZoom); // return 1; } var baseTheme = { colors: { background: "rgb(246, 248, 250)", text: "rgb(57, 58, 52)", primary: "rgb(0, 164, 219)" }, styles: { CodeSurfer: { pre: { color: "text", backgroundColor: "background" }, code: { color: "text", backgroundColor: "background" }, tokens: { "comment cdata doctype": { fontStyle: "italic" }, "builtin changed keyword punctuation operator tag deleted string attr-value char number inserted": { color: "primary" } }, title: { backgroundColor: "background" }, subtitle: { color: "#d6deeb", backgroundColor: "rgba(10,10,10,0.9)" }, container: {} } } }; function StylesProvider(_ref) { var _ref$theme = _ref.theme, theme = _ref$theme === void 0 ? {} : _ref$theme, children = _ref.children; var _useThemeUI = useThemeUI(), outer = _useThemeUI.theme; var base = _extends({}, baseTheme, {}, outer, { styles: _extends({}, baseTheme.styles, {}, outer.styles) }); return jsx(ThemeProvider, { theme: base }, jsx(ThemeProvider, { theme: theme }, children)); } function useStyles() { var _useThemeUI2 = useThemeUI(), theme = _useThemeUI2.theme; return theme.styles.CodeSurfer; } function getClassFromTokenType(type) { return "token-" + type; } function usePreStyle() { var styles = useStyles(); var preSx = React.useMemo(function () { var sx = _extends({}, styles.pre); Object.keys(styles.tokens).forEach(function (key) { var classList = key.split(/\s/).map(function (type) { return "." + getClassFromTokenType(type); }).join(", "); sx[classList] = styles.tokens[key]; }); return sx; }, [styles]); return preSx; } var baseTitle = { position: "absolute", top: 0, width: "100%", margin: 0, padding: "1em 0", textAlign: "center" }; var baseSubtitle = { position: "absolute", bottom: 0, width: "calc(100% - 2em)", boxSizing: "border-box", margin: "0.3em 1em", padding: "0.5em", background: "rgba(2,2,2,0.9)", textAlign: "center" }; var Styled = { Code: function Code(props) { return jsx("code", Object.assign({}, props, { sx: useStyles().code })); }, Pre: /*#__PURE__*/ React.forwardRef(function (props, ref) { return jsx("pre", Object.assign({}, props, { sx: usePreStyle(), ref: ref })); }), Title: function Title(props) { return jsx("h4", Object.assign({}, props, { sx: _extends({}, baseTitle, {}, useStyles().title) })); }, Subtitle: function Subtitle(props) { return jsx("p", Object.assign({}, props, { sx: _extends({}, baseSubtitle, {}, useStyles().subtitle) })); } }; function CodeSurferContainer(_ref) { var stepPlayhead = _ref.stepPlayhead, dimensions = _ref.dimensions, steps = _ref.steps; var ctx = useAnimationContext(steps, stepPlayhead); return React.createElement("div", { className: "cs-container", style: { width: "100%", height: dimensions ? dimensions.containerHeight : "100%", maxHeight: "100%", position: "relative" } }, React.createElement(CodeSurferContent, { dimensions: dimensions, ctx: ctx }), React.createElement(Title, { ctx: ctx.useSelect(function (step) { return step.title; }) }), React.createElement(Subtitle, { ctx: ctx.useSelect(function (step) { return step.subtitle; }) })); } var heightChangingAnimations = [{ animation: slideToLeft, when: function when(prev, next) { return prev && !next; }, stagger: 0.15 }, { animation: slideFromRight, when: function when(prev, next) { return next && !prev; }, stagger: 0.15 }, { animation: exitLine, when: function when(prev, next) { return prev && !next; } }, { animation: enterLine, when: function when(prev, next) { return next && !prev; } }]; function CodeSurferContent(_ref2) { var dimensions = _ref2.dimensions, ctx = _ref2.ctx; var ref = React.useRef(null); var _ctx$animate = ctx.animate(scrollToFocus), scrollTop = _ctx$animate.scrollTop; React.useLayoutEffect(function () { if (ref.current == null) return; ref.current.scrollTop = scrollTop; }, [scrollTop]); var _ctx$animate2 = ctx.animate(scaleToFocus), scale = _ctx$animate2.scale; var verticalOrigin = dimensions ? dimensions.containerHeight / 2 + scrollTop : 0; var linesCtx = ctx.useSelectMany(function (step) { return step.lines; }); return React.createElement(Styled.Pre, { className: "cs-content", ref: ref, style: { margin: 0, height: "100%", overflow: "hidden" } }, React.createElement(Styled.Code, { className: "cs-scaled-content", style: { display: "block", height: dimensions ? dimensions.contentHeight : "100%", width: dimensions && dimensions.contentWidth, margin: dimensions && "0 " + (dimensions.containerWidth - dimensions.contentWidth) / 2 + "px", transform: "scale(" + scale + ")", transformOrigin: "center " + verticalOrigin + "px" } }, React.createElement("div", { style: { height: dimensions && dimensions.containerHeight / 2 } }), linesCtx.map(function (ctx, key) { return React.createElement(Line, { ctx: ctx, key: key }); }), React.createElement("div", { style: { height: dimensions && dimensions.containerHeight / 2 } }))); } function Line(_ref3) { var ctx = _ref3.ctx; var lineStyle = ctx.animations([].concat(heightChangingAnimations, [{ animation: focusLine }])); var _ctx$animate3 = ctx.animate(function (prev, next) { var line = prev || next; return { lineTokens: line.tokens, key: line.key, focusPerToken: prev && prev.focusPerToken || next && next.focusPerToken }; }), lineTokens = _ctx$animate3.lineTokens, key = _ctx$animate3.key, focusPerToken = _ctx$animate3.focusPerToken; var tokens = []; var tokensCtx = ctx.useSelectMany(function (line) { return line.tokens; }); if (focusPerToken) { tokens = tokensCtx.map(function (tokenCtx) { return _extends({}, tokenCtx.animate(function (prev, next) { return prev || next; }), { animatedStyle: tokenCtx.animate(focusToken) }); }); } else { tokens = lineTokens.map(function (token) { return _extends({}, token, { animatedStyle: {} }); }); } return React.createElement("div", { style: _extends({ overflow: "hidden" }, lineStyle) }, React.createElement("div", { style: { display: "inline-block" }, className: "cs-line cs-line-" + key }, tokens.map(function (token, i) { return React.createElement("span", { key: i, style: token.animatedStyle, className: getClassFromTokenType(token.type) }, token.content); }))); } function Title(_ref4) { var ctx = _ref4.ctx; var text = ctx.animate(switchText); var bgStyle = ctx.animate(fadeBackground); var textStyle = ctx.animate(fadeText); if (!text) return null; return React.createElement(Styled.Title, { className: "cs-title", style: bgStyle }, React.createElement("span", { style: textStyle }, text)); } function Subtitle(_ref5) { var ctx = _ref5.ctx; var text = ctx.animate(switchText); var bgStyle = ctx.animate(fadeBackground); var textStyle = ctx.animate(fadeText); if (!text) return null; return React.createElement(Styled.Subtitle, { className: "cs-subtitle", style: bgStyle }, React.createElement("span", { style: textStyle }, text)); } var fadeBackground = function fadeBackground(prev, next, t) { var opacity = 1; if (!prev) { opacity = t; } if (!next) { opacity = 1 - t; } return { opacity: opacity }; }; var fadeText = function fadeText(prev, next, t) { if (prev && next && prev.value !== next.value) { return fadeOutIn(t); } if (!prev) { return fadeIn(t); } if (!next) { return fadeOut(t); } return { opacity: 1 }; }; function useWindowResize(handler, deps) { React.useEffect(function () { window.addEventListener("resize", handler); return function () { window.removeEventListener("resize", handler); }; }, deps); } function useDimensions(ref, steps) { var _React$useState = React.useState(null), result = _React$useState[0], setResult = _React$useState[1]; useWindowResize(function () { return setResult(null); }, [setResult]); React.useLayoutEffect(function () { if (!ref.current) return; if (result) return; var containers = ref.current.querySelectorAll(".cs-container"); var stepsDimensions = Array.from(containers).map(function (container, i) { return getStepDimensions(container, steps[i]); }); var containerHeight = Math.max.apply(Math, stepsDimensions.map(function (d) { return d.containerHeight; })); var containerWidth = Math.max.apply(Math, stepsDimensions.map(function (d) { return d.containerWidth; })); var contentWidth = Math.max.apply(Math, stepsDimensions.map(function (d) { return d.contentWidth; })); var lineHeight = Math.max.apply(Math, stepsDimensions.map(function (d) { return d.lineHeight; })); setResult({ dimensions: { lineHeight: lineHeight, contentWidth: contentWidth, containerHeight: containerHeight, containerWidth: containerWidth }, steps: steps.map(function (step, i) { return _extends({}, step, { lines: step.lines.map(function (l) { return _extends({}, l, { dimensions: { lineHeight: stepsDimensions[i].lineHeight } }); }), dimensions: { paddingTop: stepsDimensions[i].paddingTop, paddingBottom: stepsDimensions[i].paddingBottom, lineHeight: stepsDimensions[i].lineHeight, contentWidth: contentWidth, containerHeight: containerHeight, containerWidth: containerWidth } }); }) }); }, [result]); return result || {}; } function getStepDimensions(container, step) { var longestLine = getLongestLine(step); var longestLineKey = longestLine && longestLine.key; var longestLineSpan = container.querySelector(".cs-line-" + longestLineKey); var containerParent = container.parentElement; var title = container.querySelector(".cs-title"); var subtitle = container.querySelector(".cs-subtitle"); var lineCount = step.lines.length; var heightOverflow = containerParent.scrollHeight - containerParent.clientHeight; var avaliableHeight = container.scrollHeight - heightOverflow; var lineHeight = longestLineSpan ? longestLineSpan.clientHeight : 0; var paddingTop = title ? outerHeight(title) : lineHeight; var paddingBottom = subtitle ? outerHeight(subtitle) : lineHeight; var codeHeight = lineCount * lineHeight * 2; // const maxContentHeight = codeHeight + paddingTop + paddingBottom; // const containerHeight = Math.min(maxContentHeight, avaliableHeight); var containerHeight = avaliableHeight; var containerWidth = container.clientWidth; var contentHeight = codeHeight + containerHeight; var contentWidth = longestLineSpan ? longestLineSpan.clientWidth : 0; return { lineHeight: lineHeight, contentHeight: contentHeight, contentWidth: contentWidth, paddingTop: paddingTop, paddingBottom: paddingBottom, containerHeight: containerHeight, containerWidth: containerWidth }; } function outerHeight(element) { var styles = window.getComputedStyle(element); var margin = parseFloat(styles["marginTop"] || "0") + parseFloat(styles["marginBottom"] || "0"); return element.offsetHeight + margin; } function getLongestLine(step) { if (!step || step.lines.length === 0) { return null; } return step.lines.reduce(function (a, b) { return a.content.length > b.content.length ? a : b; }); } function makeTheme(prismTheme, override) { if (override === void 0) { override = {}; } var tokens = {}; prismTheme.styles.forEach(function (s) { tokens[s.types.join(" ")] = s.style; }); return { styles: { CodeSurfer: _extends({ tokens: tokens, title: { backgroundColor: prismTheme.plain.backgroundColor }, subtitle: { color: "#d6deeb", backgroundColor: "rgba(10,10,10,0.9)" }, pre: { color: prismTheme.plain.color, backgroundColor: prismTheme.plain.backgroundColor }, code: { color: prismTheme.plain.color, backgroundColor: prismTheme.plain.backgroundColor } }, override) } }; } var prismTheme = { plain: { color: "#393A34", backgroundColor: "#f6f8fa" }, styles: [{ types: ["comment", "prolog", "doctype", "cdata"], style: { color: "#999988", fontStyle: "italic" } }, { types: ["namespace"], style: { opacity: 0.7 } }, { types: ["string", "attr-value"], style: { color: "#e3116c" } }, { types: ["punctuation", "operator"], style: { color: "#393A34" } }, { types: ["entity", "url", "symbol", "number", "boolean", "variable", "constant", "property", "regex", "inserted"], style: { color: "#36acaa" } }, { types: ["atrule", "keyword", "attr-name", "selector"], style: { color: "#00a4db" } }, { types: ["function", "deleted", "tag"], style: { color: "#d73a49" } }, { types: ["function-variable"], style: { color: "#6f42c1" } }, { types: ["tag", "selector"], style: { color: "#00009f" } }] }; var theme = /*#__PURE__*/ makeTheme(prismTheme); var prismTheme$1 = { plain: { color: "#F8F8F2", backgroundColor: "#282A36" }, styles: [{ types: ["prolog", "constant", "builtin"], style: { color: "rgb(189, 147, 249)" } }, { types: ["inserted", "function"], style: { color: "rgb(80, 250, 123)" } }, { types: ["deleted"], style: { color: "rgb(255, 85, 85)" } }, { types: ["changed"], style: { color: "rgb(255, 184, 108)" } }, { types: ["punctuation", "symbol"], style: { color: "rgb(248, 248, 242)" } }, { types: ["string", "char", "tag", "selector"], style: { color: "rgb(255, 121, 198)" } }, { types: ["keyword", "variable"], style: { color: "rgb(189, 147, 249)", fontStyle: "italic" } }, { types: ["comment"], style: { color: "rgb(98, 114, 164)" } }, { types: ["attr-name"], style: { color: "rgb(241, 250, 140)" } }] }; var theme$1 = /*#__PURE__*/ makeTheme(prismTheme$1); var prismTheme$2 = { plain: { backgroundColor: "#2a2734", color: "#9a86fd" }, styles: [{ types: ["comment", "prolog", "doctype", "cdata", "punctuation"], style: { color: "#6c6783" } }, { types: ["namespace"], style: { opacity: 0.7 } }, { types: ["tag", "operator", "number"], style: { color: "#e09142" } }, { types: ["property", "function"], style: { color: "#9a86fd" } }, { types: ["tag-id", "selector", "atrule-id"], style: {