From 84f43ab949834b5cfd0872258754e91f54964988 Mon Sep 17 00:00:00 2001 From: Rodrigo Pombo Date: Mon, 5 Apr 2021 12:03:02 -0300 Subject: [PATCH] Rename editor components --- external/new-react-website | 2 +- packages/mini-editor/src/index.tsx | 12 +- packages/mini-editor/src/mini-editor-hike.tsx | 262 ++++++++++++ packages/mini-editor/src/mini-editor.tsx | 284 ++----------- packages/mini-editor/src/stateful-editor.tsx | 55 --- packages/scrollycoding/src/code.tsx | 4 +- packages/scrollycoding/src/hike-context.tsx | 4 +- .../storybook/src/editor-with-state.story.js | 53 --- .../storybook/src/mini-editor-hike.story.js | 376 +++++++++++++++++ packages/storybook/src/mini-editor.story.js | 385 ++---------------- 10 files changed, 720 insertions(+), 717 deletions(-) create mode 100644 packages/mini-editor/src/mini-editor-hike.tsx delete mode 100644 packages/mini-editor/src/stateful-editor.tsx delete mode 100644 packages/storybook/src/editor-with-state.story.js create mode 100644 packages/storybook/src/mini-editor-hike.story.js diff --git a/external/new-react-website b/external/new-react-website index b9f3ea87..89fd83de 160000 --- a/external/new-react-website +++ b/external/new-react-website @@ -1 +1 @@ -Subproject commit b9f3ea8702d47c074d5592004615bdb852ebd80e +Subproject commit 89fd83dec2ebbbe90917b00363cb67129f91275f diff --git a/packages/mini-editor/src/index.tsx b/packages/mini-editor/src/index.tsx index 27c1b52e..4b025c45 100644 --- a/packages/mini-editor/src/index.tsx +++ b/packages/mini-editor/src/index.tsx @@ -1,14 +1,14 @@ import "./index.scss" -import { MiniEditor, MiniEditorProps } from "./mini-editor" import { - MiniEditorWithState, - StatefulEditorProps, -} from "./stateful-editor" + MiniEditorHike, + MiniEditorHikeProps, +} from "./mini-editor-hike" +import { MiniEditor, MiniEditorProps } from "./mini-editor" export { + MiniEditorHike, MiniEditor, - MiniEditorWithState, + MiniEditorHikeProps, MiniEditorProps, - StatefulEditorProps, } diff --git a/packages/mini-editor/src/mini-editor-hike.tsx b/packages/mini-editor/src/mini-editor-hike.tsx new file mode 100644 index 00000000..6856bce1 --- /dev/null +++ b/packages/mini-editor/src/mini-editor-hike.tsx @@ -0,0 +1,262 @@ +import React from "react" +import { EditorFrame, TerminalPanel } from "./editor-frame" +import { InnerTerminal } from "@code-hike/mini-terminal" +import { Code } from "./code" +import { + useBackwardTransitions, + useForwardTransitions, +} from "./steps" +import { Classes } from "@code-hike/classer" +// import "./theme.css" + +export { MiniEditorHike } + +type MiniEditorStep = { + code?: string + focus?: string + lang?: string + file?: string + tabs?: string[] + terminal?: string +} + +export type MiniEditorHikeProps = { + progress?: number + backward?: boolean + code?: string + focus?: string + lang?: string + file?: string + tabs?: string[] + steps?: MiniEditorStep[] + height?: number + minColumns?: number + minZoom?: number + maxZoom?: number + button?: React.ReactNode + classes?: Classes +} & React.PropsWithoutRef + +function MiniEditorHike(props: MiniEditorHikeProps) { + const { + progress = 0, + backward = false, + code, + focus, + lang, + file, + steps: ogSteps, + tabs: ogTabs, + minColumns = 50, + minZoom = 0.2, + maxZoom = 1, + height, + ...rest + } = props + const { steps, files, stepsByFile } = useSteps(ogSteps, { + code, + focus, + lang, + file, + tabs: ogTabs, + }) + + const activeStepIndex = backward + ? Math.floor(progress) + : Math.ceil(progress) + const activeStep = steps[activeStepIndex] + const activeFile = (activeStep && activeStep.file) || "" + + const activeSteps = stepsByFile[activeFile] || [] + + const tabs = activeStep.tabs || files + + const terminalHeight = getTerminalHeight(steps, progress) + + const terminalSteps = steps.map(s => ({ + text: (s && s.terminal) || "", + })) + + const contentSteps = useStepsWithDefaults( + { code, focus, lang, file }, + ogSteps || [] + ) + + return ( + + + + } + height={height} + {...rest} + > + {activeSteps.length > 0 && ( + + )} + + ) +} + +function useStepsWithDefaults( + defaults: MiniEditorStep, + steps: MiniEditorStep[] +): ContentStep[] { + const files = [ + ...new Set( + steps.map(s => coalesce(s.file, defaults.file, "")) + ), + ] + return steps.map(step => { + return { + code: coalesce(step.code, defaults.code, ""), + file: coalesce(step.file, defaults.file, ""), + focus: coalesce(step.focus, defaults.focus, ""), + lang: coalesce( + step.lang, + defaults.lang, + "javascript" + ), + tabs: coalesce(step.tabs, defaults.tabs, files), + terminal: step.terminal || defaults.terminal, + } + }) +} + +function coalesce( + a: T | null | undefined, + b: T | null | undefined, + c: T +): T { + return a != null ? a : b != null ? b : c +} + +type ContentStep = { + code: string + focus: string + lang: string + file: string + tabs: string[] + terminal?: string +} + +type ContentProps = { + progress: number + backward: boolean + steps: ContentStep[] + parentHeight?: number + minColumns: number + minZoom: number + maxZoom: number +} + +function EditorContent({ + progress, + backward, + steps, + parentHeight, + minColumns, + minZoom, + maxZoom, +}: ContentProps) { + const fwdTransitions = useForwardTransitions(steps) + const bwdTransitions = useBackwardTransitions(steps) + + const transitionIndex = Math.ceil(progress) + const { + prevCode, + nextCode, + prevFocus, + nextFocus, + lang, + } = backward + ? bwdTransitions[transitionIndex] + : fwdTransitions[transitionIndex] + + return ( + + ) +} + +function useSteps( + ogSteps: MiniEditorStep[] | undefined, + { code = "", focus, lang, file, tabs }: MiniEditorStep +) { + return React.useMemo(() => { + const steps = ogSteps?.map(s => ({ + code, + focus, + lang, + file, + tabs, + ...s, + })) || [{ code, focus, lang, file, tabs }] + + const files = [ + ...new Set( + steps + .map((s: any) => s.file) + .filter((f: any) => f != null) + ), + ] + + const stepsByFile: Record = {} + steps.forEach(s => { + if (s.file == null) return + if (!stepsByFile[s.file]) { + stepsByFile[s.file] = [] + } + stepsByFile[s.file].push(s) + }) + + return { steps, files, stepsByFile } + }, [ogSteps, code, focus, lang, file, tabs]) +} + +const MAX_HEIGHT = 150 +function getTerminalHeight(steps: any, progress: number) { + if (!steps.length) { + return 0 + } + + const prevIndex = Math.floor(progress) + const nextIndex = Math.ceil(progress) + const prevTerminal = + steps[prevIndex] && steps[prevIndex].terminal + const nextTerminal = steps[nextIndex].terminal + + if (!prevTerminal && !nextTerminal) return 0 + + if (!prevTerminal && nextTerminal) + return MAX_HEIGHT * Math.min((progress % 1) * 4, 1) + if (prevTerminal && !nextTerminal) + return MAX_HEIGHT * Math.max(1 - (progress % 1) * 4, 0) + + return MAX_HEIGHT +} diff --git a/packages/mini-editor/src/mini-editor.tsx b/packages/mini-editor/src/mini-editor.tsx index 16e8c88e..f3a6fd6e 100644 --- a/packages/mini-editor/src/mini-editor.tsx +++ b/packages/mini-editor/src/mini-editor.tsx @@ -1,262 +1,58 @@ import React from "react" -import { EditorFrame, TerminalPanel } from "./editor-frame" -import { InnerTerminal } from "@code-hike/mini-terminal" -import { Code } from "./code" +import { useSpring } from "use-spring" import { - useBackwardTransitions, - useForwardTransitions, -} from "./steps" -import { Classes } from "@code-hike/classer" -// import "./theme.css" + MiniEditorHike, + MiniEditorHikeProps, +} from "./mini-editor-hike" export { MiniEditor } -type MiniEditorStep = { - code?: string - focus?: string - lang?: string - file?: string - tabs?: string[] - terminal?: string -} - -export type MiniEditorProps = { - progress?: number - backward?: boolean - code?: string - focus?: string - lang?: string - file?: string - tabs?: string[] - steps?: MiniEditorStep[] - height?: number - minColumns?: number - minZoom?: number - maxZoom?: number - button?: React.ReactNode - classes?: Classes -} & React.PropsWithoutRef - -function MiniEditor(props: MiniEditorProps) { - const { - progress = 0, - backward = false, - code, - focus, - lang, - file, - steps: ogSteps, - tabs: ogTabs, - minColumns = 50, - minZoom = 0.2, - maxZoom = 1, - height, - ...rest - } = props - const { steps, files, stepsByFile } = useSteps(ogSteps, { - code, - focus, - lang, - file, - tabs: ogTabs, - }) - - const activeStepIndex = backward - ? Math.floor(progress) - : Math.ceil(progress) - const activeStep = steps[activeStepIndex] - const activeFile = (activeStep && activeStep.file) || "" - - const activeSteps = stepsByFile[activeFile] || [] - - const tabs = activeStep.tabs || files - - const terminalHeight = getTerminalHeight(steps, progress) - - const terminalSteps = steps.map(s => ({ - text: (s && s.terminal) || "", - })) +export type MiniEditorProps = Omit< + MiniEditorHikeProps, + "progress" | "steps" | "backward" +> - const contentSteps = useStepsWithDefaults( - { code, focus, lang, file }, - ogSteps || [] - ) +function MiniEditor({ + focus, + code, + ...rest +}: MiniEditorProps) { + const [steps, progress] = usePrevFocus(code, focus) return ( - - - - } - height={height} + - {activeSteps.length > 0 && ( - - )} - - ) -} - -function useStepsWithDefaults( - defaults: MiniEditorStep, - steps: MiniEditorStep[] -): ContentStep[] { - const files = [ - ...new Set( - steps.map(s => coalesce(s.file, defaults.file, "")) - ), - ] - return steps.map(step => { - return { - code: coalesce(step.code, defaults.code, ""), - file: coalesce(step.file, defaults.file, ""), - focus: coalesce(step.focus, defaults.focus, ""), - lang: coalesce( - step.lang, - defaults.lang, - "javascript" - ), - tabs: coalesce(step.tabs, defaults.tabs, files), - terminal: step.terminal || defaults.terminal, - } - }) -} - -function coalesce( - a: T | null | undefined, - b: T | null | undefined, - c: T -): T { - return a != null ? a : b != null ? b : c -} - -type ContentStep = { - code: string - focus: string - lang: string - file: string - tabs: string[] - terminal?: string -} - -type ContentProps = { - progress: number - backward: boolean - steps: ContentStep[] - parentHeight?: number - minColumns: number - minZoom: number - maxZoom: number -} - -function EditorContent({ - progress, - backward, - steps, - parentHeight, - minColumns, - minZoom, - maxZoom, -}: ContentProps) { - const fwdTransitions = useForwardTransitions(steps) - const bwdTransitions = useBackwardTransitions(steps) - - const transitionIndex = Math.ceil(progress) - const { - prevCode, - nextCode, - prevFocus, - nextFocus, - lang, - } = backward - ? bwdTransitions[transitionIndex] - : fwdTransitions[transitionIndex] - - return ( - ) } -function useSteps( - ogSteps: MiniEditorStep[] | undefined, - { code = "", focus, lang, file, tabs }: MiniEditorStep +function usePrevFocus( + code: string | undefined, + focus: string | undefined ) { - return React.useMemo(() => { - const steps = ogSteps?.map(s => ({ - code, - focus, - lang, - file, - tabs, - ...s, - })) || [{ code, focus, lang, file, tabs }] - - const files = [ - ...new Set( - steps - .map((s: any) => s.file) - .filter((f: any) => f != null) - ), - ] - - const stepsByFile: Record = {} - steps.forEach(s => { - if (s.file == null) return - if (!stepsByFile[s.file]) { - stepsByFile[s.file] = [] - } - stepsByFile[s.file].push(s) - }) - - return { steps, files, stepsByFile } - }, [ogSteps, code, focus, lang, file, tabs]) -} - -const MAX_HEIGHT = 150 -function getTerminalHeight(steps: any, progress: number) { - if (!steps.length) { - return 0 - } - - const prevIndex = Math.floor(progress) - const nextIndex = Math.ceil(progress) - const prevTerminal = - steps[prevIndex] && steps[prevIndex].terminal - const nextTerminal = steps[nextIndex].terminal + const [state, setState] = React.useState({ + target: 0, + steps: [{ focus, code }], + }) - if (!prevTerminal && !nextTerminal) return 0 + React.useEffect(() => { + const last = state.steps[state.steps.length - 1] + if (last.focus !== focus || last.code !== code) { + setState(s => ({ + target: s.target + 1, + steps: [...s.steps, { focus, code }], + })) + } + }, [focus, code]) - if (!prevTerminal && nextTerminal) - return MAX_HEIGHT * Math.min((progress % 1) * 4, 1) - if (prevTerminal && !nextTerminal) - return MAX_HEIGHT * Math.max(1 - (progress % 1) * 4, 0) + const [progress] = useSpring(state.target, { + stiffness: 256, + damping: 24, + mass: 0.2, + decimals: 3, + }) - return MAX_HEIGHT + return [state.steps, progress] as const } diff --git a/packages/mini-editor/src/stateful-editor.tsx b/packages/mini-editor/src/stateful-editor.tsx deleted file mode 100644 index ba193b29..00000000 --- a/packages/mini-editor/src/stateful-editor.tsx +++ /dev/null @@ -1,55 +0,0 @@ -import React from "react" -import { useSpring } from "use-spring" -import { MiniEditor, MiniEditorProps } from "./mini-editor" - -export { MiniEditorWithState } - -export type StatefulEditorProps = Omit< - MiniEditorProps, - "progress" | "steps" | "backward" -> - -function MiniEditorWithState({ - focus, - code, - ...rest -}: StatefulEditorProps) { - const [steps, progress] = usePrevFocus(code, focus) - - return ( - - ) -} - -function usePrevFocus( - code: string | undefined, - focus: string | undefined -) { - const [state, setState] = React.useState({ - target: 0, - steps: [{ focus, code }], - }) - - React.useEffect(() => { - const last = state.steps[state.steps.length - 1] - if (last.focus !== focus || last.code !== code) { - setState(s => ({ - target: s.target + 1, - steps: [...s.steps, { focus, code }], - })) - } - }, [focus, code]) - - const [progress] = useSpring(state.target, { - stiffness: 256, - damping: 24, - mass: 0.2, - decimals: 3, - }) - - return [state.steps, progress] as const -} diff --git a/packages/scrollycoding/src/code.tsx b/packages/scrollycoding/src/code.tsx index 70ca11bf..3fec13c4 100644 --- a/packages/scrollycoding/src/code.tsx +++ b/packages/scrollycoding/src/code.tsx @@ -1,5 +1,5 @@ import * as React from "react" -import { MiniEditorWithState } from "@code-hike/mini-editor" +import { MiniEditor } from "@code-hike/mini-editor" import { CodeProps } from "./hike-context" import { useCodeSandboxLink } from "@codesandbox/sandpack-react" @@ -11,7 +11,7 @@ function Code({ files, activeFile, ...props }: CodeProps) { filename => !files[filename].hideTab ) return ( - +} & Omit export interface HikeStep { content: React.ReactNode[] diff --git a/packages/storybook/src/editor-with-state.story.js b/packages/storybook/src/editor-with-state.story.js deleted file mode 100644 index 7f4a7720..00000000 --- a/packages/storybook/src/editor-with-state.story.js +++ /dev/null @@ -1,53 +0,0 @@ -import React from "react" -import { MiniEditorWithState as Editor } from "@code-hike/mini-editor" -import { Page } from "./utils" -import "@code-hike/mini-editor/dist/index.css" - -export default { - title: "Mini Editor With State", -} - -const code1 = `console.log(1) -console.log(2) -console.log(3) -console.log(4) -console.log(5)` - -export const focusEditor = () => { - const [input, setInput] = React.useState("1:5") - const [focus, setFocus] = React.useState(null) - return ( - -
- setInput(e.target.value)} - /> - -
- -
- ) -} - -export const codeEditor = () => { - const [input, setInput] = React.useState(code1) - const [code, setCode] = React.useState(code1) - return ( - -
-