diff --git a/packages/mini-editor/package.json b/packages/mini-editor/package.json index 7814c8ae..94a94c62 100644 --- a/packages/mini-editor/package.json +++ b/packages/mini-editor/package.json @@ -18,10 +18,9 @@ }, "dependencies": { "@code-hike/classer": "^0.3.0-next.0", - "@code-hike/code-diff": "^0.3.0-next.0", "@code-hike/mini-frame": "^0.3.0-next.0", "@code-hike/mini-terminal": "^0.3.0-next.0", - "@code-hike/smooth-lines": "^0.3.0-next.0", + "@code-hike/smooth-code": "^0.3.0-next.0", "use-spring": "^0.2.3" }, "peerDependencies": { diff --git a/packages/mini-editor/src/code-tween.tsx b/packages/mini-editor/src/code-tween.tsx deleted file mode 100644 index abaee852..00000000 --- a/packages/mini-editor/src/code-tween.tsx +++ /dev/null @@ -1,352 +0,0 @@ -import React from "react" -import { codeDiff, CodeLine } from "@code-hike/code-diff" -import { SmoothLines } from "@code-hike/smooth-lines" -import { useDimensions } from "./use-dimensions" -import { - getFocusByKey, - getFocusIndexes, -} from "./focus-parser" - -interface CodeTweenProps { - /** A number between 0 and 1. */ - progress: number - /** The code to show when progress is 0. */ - prevCode: string - /** The code to show when progress is 1. */ - nextCode: string - /** The code to focus when progress is 0. */ - prevFocus: string | null - /** The code to focus when progress is 1. */ - nextFocus: string | null - /** - * The language used to tokenize the code. - * (you may need to import the language from prism) - */ - language: string - /** - * Ensure that we show at least `minColumns` of width - * even when the largest line has less columns. - */ - minColumns: number - /** - * The available space for the code is memoized, - * so, if `parentHeight` changes between renders - * we recalculate the dimensions for the code. - */ - parentHeight?: number -} - -export { CodeTween } - -/** - * Transitions between to pieces of code. - * When `progress` is 0 it shows `prevCode`, - * when `progress` is 1 it shows `nextCode`, - * when `progress` is 0.5 its halfway between - * `prevCode` and `nextCode`. - */ -function CodeTween({ - prevCode, - prevFocus, - nextCode, - nextFocus, - progress, - language, - parentHeight, - minColumns, -}: CodeTweenProps) { - const { - prevLines, - nextLines, - prevFocusIndexes, - nextFocusIndexes, - prevLongestLine, - nextLongestLine, - } = useLineProps( - prevCode, - nextCode, - language, - prevFocus, - nextFocus - ) - - const [ref, dimensions] = useDimensions([ - parentHeight, - prevLongestLine, - nextLongestLine, - ]) - - return ( -
-      
-        {dimensions ? (
-          
-                Math.max(
-                  lw,
-                  dimensions.colWidth * minColumns
-                )
-              ) as [number, number]
-            }
-            prevFocus={prevFocusIndexes}
-            nextFocus={nextFocusIndexes}
-            maxZoom={1}
-          />
-        ) : (
-          <>
-            
- {prevLongestLine} -
-
- {nextLongestLine} -
- - )} -
-
- ) -} - -function useLineProps( - prevCode: string, - nextCode: string, - language: string, - prevFocus: string | null, - nextFocus: string | null -) { - return React.useMemo(() => { - const { prevKeys, nextKeys, codeMap } = codeDiff({ - prevCode, - nextCode, - lang: language, - }) - - const prevFocusByKey = getFocusByKey( - prevFocus, - prevKeys - ) - const prevFocusIndexes = getFocusIndexes( - prevFocus, - prevKeys - ) - const prevLongestLineIndex = longestLineIndex( - prevCode, - prevFocusIndexes - ) - - const nextFocusByKey = getFocusByKey( - nextFocus, - nextKeys - ) - const nextFocusIndexes = getFocusIndexes( - nextFocus, - nextKeys - ) - const nextLongestLineIndex = longestLineIndex( - nextCode, - nextFocusIndexes - ) - - const prevLines = prevKeys.map(key => { - const prevFocus = prevFocusByKey[key] - const nextFocus = nextFocusByKey[key] - const focusPerColumn = - Array.isArray(prevFocus) || Array.isArray(nextFocus) - if (!focusPerColumn) { - return { - key, - element: , - } - } else { - return { - key, - element: , - elementWithProgress: (progress: number) => ( - - ), - } - } - }) - const prevLongestLine = - prevLongestLineIndex == null - ? null - : prevLines[prevLongestLineIndex]?.element - - const nextLines = nextKeys.map(key => { - const prevFocus = prevFocusByKey[key] - const nextFocus = nextFocusByKey[key] - const focusPerColumn = - Array.isArray(prevFocus) || Array.isArray(nextFocus) - if (!focusPerColumn) { - return { - key, - element: , - } - } else { - return { - key, - element: , - elementWithProgress: (progress: number) => ( - - ), - } - } - }) - const nextLongestLine = - nextLongestLineIndex == null - ? null - : nextLines[nextLongestLineIndex]?.element - - return { - prevLines, - nextLines, - prevFocusIndexes, - nextFocusIndexes, - prevLongestLine, - nextLongestLine, - } - }, [prevCode, nextCode, language, prevFocus, nextFocus]) -} - -function Line({ line }: { line: CodeLine }) { - return ( -
- {line.map(([token, type], i) => ( - - {token} - - ))} -
- ) -} - -const OFF_OPACITY = 0.33 - -function ColumnedLine({ - line, - progress, - prevFocus, - nextFocus, -}: { - line: CodeLine - progress: number - prevFocus: undefined | boolean | number[] - nextFocus: undefined | boolean | number[] -}) { - const columns = React.useMemo(() => { - const chars = flatMap(line, ([token, type]) => - token.split("").map(char => [char, type]) - ) - - return chars.map(([char, type], i) => ({ - char, - type, - fromOpacity: !prevFocus - ? 0.99 // because the line is already transparent - : prevFocus === true || prevFocus.includes(i) - ? 0.99 - : OFF_OPACITY, - toOpacity: !nextFocus - ? 0.99 // because the line is already transparent - : nextFocus === true || nextFocus.includes(i) - ? 0.99 - : OFF_OPACITY, - })) - }, [line, prevFocus, nextFocus]) - - return ( -
- {columns.map( - ({ char, type, fromOpacity, toOpacity }, i) => ( - - {char} - - ) - )} -
- ) -} - -function tween(p: number, n: number, t: number) { - return (n - p) * t + p -} - -const newlineRe = /\r\n|\r|\n/ -function longestLineIndex( - code: string, - focusIndexes: number[] -) { - const first = Math.min(...focusIndexes) - const last = Math.max(...focusIndexes) - const focusedLines = - code == null - ? [] - : code.split(newlineRe).slice(first, last + 1) - - if (!focusedLines.length) { - return null - } - - let longestIndex = 0 - for (let i = 1; i < focusedLines.length; i++) { - if ( - focusedLines[i].length > - focusedLines[longestIndex].length - ) { - longestIndex = i - } - } - return first + longestIndex -} - -export function flatMap( - array: T[], - callbackfn: (value: T, index: number, array: T[]) => U[] -): U[] { - return Array.prototype.concat(...array.map(callbackfn)) -} diff --git a/packages/mini-editor/src/mini-editor-hike.tsx b/packages/mini-editor/src/mini-editor-hike.tsx index daca4c43..f721a677 100644 --- a/packages/mini-editor/src/mini-editor-hike.tsx +++ b/packages/mini-editor/src/mini-editor-hike.tsx @@ -1,7 +1,7 @@ import React from "react" import { MiniEditorTween } from "./mini-editor-tween" import { EditorStep } from "./use-snapshots" -import { CodeProps } from "./code" +import { CodeProps } from "@code-hike/smooth-code" import { EditorFrameProps } from "./editor-frame" export { MiniEditorHike, MiniEditorHikeProps, EditorStep } diff --git a/packages/mini-editor/src/mini-editor-spring.tsx b/packages/mini-editor/src/mini-editor-spring.tsx index 74b18cc8..602abf32 100644 --- a/packages/mini-editor/src/mini-editor-spring.tsx +++ b/packages/mini-editor/src/mini-editor-spring.tsx @@ -2,7 +2,7 @@ import React from "react" import { useSpring } from "use-spring" import { MiniEditorTween } from "./mini-editor-tween" import { EditorStep, StepFile } from "./use-snapshots" -import { CodeProps } from "./code" +import { CodeProps } from "@code-hike/smooth-code" import { EditorFrameProps } from "./editor-frame" export { MiniEditor, MiniEditorProps } diff --git a/packages/mini-editor/src/mini-editor-tween.tsx b/packages/mini-editor/src/mini-editor-tween.tsx index aecdc168..7aa17e58 100644 --- a/packages/mini-editor/src/mini-editor-tween.tsx +++ b/packages/mini-editor/src/mini-editor-tween.tsx @@ -5,7 +5,7 @@ import { getPanelStyles, OutputPanel, } from "./editor-frame" -import { Code, CodeProps } from "./code" +import { Code, CodeProps } from "@code-hike/smooth-code" import { EditorStep, StepFile, diff --git a/packages/smooth-code/package.json b/packages/smooth-code/package.json new file mode 100644 index 00000000..b3cbb45f --- /dev/null +++ b/packages/smooth-code/package.json @@ -0,0 +1,37 @@ +{ + "name": "@code-hike/smooth-code", + "version": "0.3.0-next.0", + "main": "dist/index.cjs.js", + "typings": "dist/index.d.ts", + "module": "dist/index.esm.js", + "style": "dist/index.css", + "files": [ + "dist" + ], + "scripts": { + "x": "x" + }, + "devDependencies": { + "@code-hike/script": "0.0.1", + "@types/react": "^16.9.38", + "react": "^16.13.1" + }, + "dependencies": { + "@code-hike/code-diff": "^0.3.0-next.0", + "@code-hike/smooth-lines": "^0.3.0-next.0" + }, + "peerDependencies": { + "react": ">=16.8" + }, + "keywords": [ + "react" + ], + "homepage": "https://codehike.org", + "repository": "code-hike/codehike", + "author": "Rodrigo Pombo", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/codehike" + } +} diff --git a/packages/smooth-code/readme.md b/packages/smooth-code/readme.md new file mode 100644 index 00000000..2a3bd5f6 --- /dev/null +++ b/packages/smooth-code/readme.md @@ -0,0 +1 @@ +See [codehike.org](https://codehike.org) diff --git a/packages/mini-editor/src/code.tsx b/packages/smooth-code/src/code.tsx similarity index 100% rename from packages/mini-editor/src/code.tsx rename to packages/smooth-code/src/code.tsx diff --git a/packages/mini-editor/src/focus-parser.ts b/packages/smooth-code/src/focus-parser.ts similarity index 100% rename from packages/mini-editor/src/focus-parser.ts rename to packages/smooth-code/src/focus-parser.ts diff --git a/packages/smooth-code/src/index.tsx b/packages/smooth-code/src/index.tsx new file mode 100644 index 00000000..c7500a83 --- /dev/null +++ b/packages/smooth-code/src/index.tsx @@ -0,0 +1,3 @@ +import { Code, CodeProps } from "./code" + +export { Code, CodeProps } diff --git a/packages/mini-editor/src/use-dimensions.tsx b/packages/smooth-code/src/use-dimensions.tsx similarity index 100% rename from packages/mini-editor/src/use-dimensions.tsx rename to packages/smooth-code/src/use-dimensions.tsx diff --git a/packages/smooth-code/tsconfig.json b/packages/smooth-code/tsconfig.json new file mode 100644 index 00000000..8b1dd15e --- /dev/null +++ b/packages/smooth-code/tsconfig.json @@ -0,0 +1,12 @@ +{ + "extends": "../tsconfig.json", + "include": ["src", "types"], + "compilerOptions": { + "rootDir": "./src", + "baseUrl": "./", + "paths": { + "@": ["./"], + "*": ["src/*", "node_modules/*"] + } + } +}