diff --git a/packages/highlighter/package.json b/packages/highlighter/package.json index e0324035..bcaac602 100644 --- a/packages/highlighter/package.json +++ b/packages/highlighter/package.json @@ -17,7 +17,7 @@ }, "dependencies": { "@code-hike/utils": "^0.3.0-next.0", - "shiki": "^0.9.11" + "shiki": "^0.9.14" }, "homepage": "https://codehike.org", "repository": "code-hike/codehike", diff --git a/packages/playground/content/meta-annotations.mdx b/packages/playground/content/meta-annotations.mdx index 7c4f1ffa..dacfc874 100644 --- a/packages/playground/content/meta-annotations.mdx +++ b/packages/playground/content/meta-annotations.mdx @@ -6,7 +6,7 @@ Besides `focus`, there are a few more annotations that can be used to highlight ### `box` annotation -```js box=2[15:43] +```js box=2[15:43],4[10:12] function lorem(ipsum, dolor = 1) { const sit = ipsum == null ? 0 : ipsum.sit dolor = sit - amet(dolor) @@ -18,7 +18,7 @@ function lorem(ipsum, dolor = 1) { ### `bg` annotation -```js bg=4:6 +```js bg=2,4:6 function lorem(ipsum, dolor = 1) { const sit = ipsum == null ? 0 : ipsum.sit dolor = sit - amet(dolor) diff --git a/packages/smooth-code/src/annotations.tsx b/packages/smooth-code/src/annotations.tsx index febe8b53..f6ac316e 100644 --- a/packages/smooth-code/src/annotations.tsx +++ b/packages/smooth-code/src/annotations.tsx @@ -7,7 +7,7 @@ import { FocusedLine, AnnotatedLine, LineGroup, -} from "./step-parser" +} from "./partial-step-parser" import { Tween, FullTween, @@ -15,6 +15,7 @@ import { map, hasColumns, parsePartToObject, + splitParts, ColumnExtremes, parseExtremes, } from "@code-hike/utils" @@ -32,13 +33,27 @@ export function parseAnnotations( > multilineAnnotations: FullTween } { - const inlineCodeAnnotations = mapWithDefault( + // split annotations with multiple parts in the focus string + // "1:2,3[4:5]" becomes two annotations "1:2" and "3[4:5]" + const expandedAnnotations = mapWithDefault( annotations, [], + annotations => + annotations!.flatMap(annotation => + splitParts(annotation.focus).map(part => ({ + ...annotation, + focus: part, + })) + ) + ) + + const inlineCodeAnnotations = mapWithDefault( + expandedAnnotations, + [], annotations => annotations!.filter(isInline) ) const multilineCodeAnnotations = mapWithDefault( - annotations, + expandedAnnotations, [], annotations => annotations!.filter(a => !isInline(a)) ) diff --git a/packages/smooth-code/src/differ.ts b/packages/smooth-code/src/differ.ts index d561989c..19dc78b5 100644 --- a/packages/smooth-code/src/differ.ts +++ b/packages/smooth-code/src/differ.ts @@ -4,7 +4,7 @@ import { HighlightedLine, MergedCode, MergedLine, -} from "./step-parser" +} from "./partial-step-parser" export function mergeLines( code: FullTween, diff --git a/packages/smooth-code/src/heavy-code.tsx b/packages/smooth-code/src/heavy-code.tsx deleted file mode 100644 index e6b6a98d..00000000 --- a/packages/smooth-code/src/heavy-code.tsx +++ /dev/null @@ -1,150 +0,0 @@ -import React from "react" -import { useDimensions, Dimensions } from "./use-dimensions" -import { IRawTheme } from "vscode-textmate" -import DEFAULT_THEME from "shiki/themes/dark-plus.json" -import { Tween, FocusString } from "@code-hike/utils" -import { - useStepParser, - CodeAnnotation, - CodeStep, -} from "./step-parser" -import { SmoothLines } from "./smooth-lines" -import { getThemeDefaultColors } from "./themes" - -type HTMLProps = React.DetailedHTMLProps< - React.HTMLAttributes, - HTMLPreElement -> - -export type CodeProps = { - code: Tween - focus: Tween - progress: number - language: string - /* not really the height, when this changes we measure everything again */ - parentHeight?: any - minColumns?: number - minZoom?: number - maxZoom?: number - horizontalCenter?: boolean - theme?: IRawTheme - htmlProps?: HTMLProps - annotations?: Tween -} - -const DEFAULT_MIN_COLUMNS = 40 - -export function HeavyCode(props: CodeProps) { - const { - code, - focus, - parentHeight, - htmlProps, - theme = (DEFAULT_THEME as unknown) as IRawTheme, - language, - annotations, - minColumns = DEFAULT_MIN_COLUMNS, - } = props - - const { element, dimensions } = useDimensions( - code, - focus, - minColumns, - [parentHeight] - ) - - const stepInfo = useStepParser({ - code, - theme, - lang: language, - focus, - annotations, - }) - - return !dimensions ? ( - - ) : ( - - ) -} - -function BeforeDimensions({ - element, - htmlProps, -}: { - element: React.ReactNode - htmlProps?: HTMLProps -}) { - return ( - - {element} - - ) -} - -function AfterDimensions({ - progress, - minZoom = 0.5, - maxZoom = 1.5, - horizontalCenter = false, - htmlProps, - theme = (DEFAULT_THEME as unknown) as IRawTheme, - dimensions, - stepInfo, -}: CodeProps & { - dimensions: NonNullable - stepInfo: CodeStep -}) { - const { bg, fg } = getThemeDefaultColors(theme) - - return ( - - - - ) -} - -function Wrapper({ - htmlProps, - style, - children, -}: { - htmlProps?: HTMLProps - style: React.CSSProperties - children: React.ReactNode -}) { - return ( -
-      {children}
-    
- ) -} diff --git a/packages/smooth-code/src/highlighter.ts b/packages/smooth-code/src/highlighter.ts deleted file mode 100644 index e8a27fa4..00000000 --- a/packages/smooth-code/src/highlighter.ts +++ /dev/null @@ -1,241 +0,0 @@ -import { - Highlighter, - setCDN, - getHighlighter, - IShikiTheme, - IThemedToken, - FontStyle, - Lang, -} from "shiki" -import { useAsyncMemo } from "./use-async-memo" -import { - Tween, - FullTween, - mapWithDefault, - map, -} from "@code-hike/utils" -import { - getThemeDefaultColors, - EditorTheme, -} from "./themes" - -type CodeToken = [ - string, - { - className?: string - style?: { color: string | undefined } - } -] -type CodeLine = CodeToken[] - -let highlighterPromise: Promise | null = null -let highlighter: Highlighter | null = null - -export function useHighlighter( - code: Tween, - lang: string, - theme: EditorTheme -): { - lines: FullTween -} { - return useAsyncMemo( - { - isReady: isHighlighterReady(lang, theme), - load: () => loadHighlighter(lang, theme), - run: () => highlightSync(code, lang, theme), - placeholder: () => { - const lines = mapWithDefault( - code, - "", - tokenizePlaceholder - ) - return { lines } - }, - }, - [code.prev, code.next, lang, theme] - ) -} - -export function isHighlighterReady( - lang: string, - theme: EditorTheme -) { - return ( - highlighter != null && - !missingTheme(highlighter, theme) && - !missingLang(highlighter, lang) - ) -} - -export async function loadHighlighter( - lang: string, - theme: EditorTheme -) { - if (highlighterPromise === null) { - setCDN("https://unpkg.com/shiki/") - highlighterPromise = getHighlighter({ - theme: theme as IShikiTheme, - langs: [lang as Lang], // TODO change lang from string to Lang - }) - } - - if (highlighter === null) { - highlighter = await highlighterPromise - } - if (missingTheme(highlighter, theme)) { - await highlighter.loadTheme(theme as IShikiTheme) - } - if (missingLang(highlighter, lang)) { - await highlighter.loadLanguage(lang as Lang) - } -} - -export function highlightOrPlaceholder( - code: string, - lang: string, - theme: EditorTheme -) { - if (isHighlighterReady(lang, theme)) { - return getCodeLines(highlighter!, code, lang, theme) - } else { - return tokenizePlaceholder(code) - } -} - -export async function highlightCode( - code: string, - lang: string, - theme: EditorTheme -) { - await loadHighlighter(lang, theme) - const { lines } = highlightSync( - { prev: code }, - lang, - theme - ) - return lines.prev.map(line => ({ - tokens: line.map(([content, props]) => ({ - content, - props, - })), - })) -} - -export async function highlightTween( - code: Tween, - lang: string, - theme: EditorTheme -) { - await loadHighlighter(lang, theme) - const { lines } = highlightSync(code, lang, theme) - return map(lines, lines => - lines.map((line, i) => ({ - tokens: line.map(([content, props]) => ({ - content, - props, - })), - })) - ) -} - -function highlightSync( - code: Tween, - lang: string, - theme: EditorTheme -) { - // assumes highlighter isReady - - const { fg, bg } = highlighter!.getTheme(theme.name) - - const lines = mapWithDefault(code, "", code => - getCodeLines(highlighter!, code, lang, theme) - ) - - return { lines, bg, fg } -} - -function getCodeLines( - highlighter: Highlighter, - code: string, - lang: string, - theme: EditorTheme -): CodeLine[] { - const lines = highlighter.codeToThemedTokens( - code, - lang, - theme.name, - { - includeExplanation: false, - } - ) - - return lines.map(line => - line.map(token => [ - token.content, - { style: getStyle(token) }, - ]) - ) -} - -function missingTheme( - highlighter: Highlighter, - theme: EditorTheme -) { - return !highlighter - .getLoadedThemes() - .some(t => t === theme.name) -} - -function missingLang( - highlighter: Highlighter, - lang: string -) { - return !highlighter - .getLoadedLanguages() - .some(l => l === lang) -} - -const FONT_STYLE_TO_CSS = { - [FontStyle.NotSet]: {}, - [FontStyle.None]: {}, - [FontStyle.Italic]: { fontStyle: "italic" }, - [FontStyle.Bold]: { fontWeight: "bold" }, - [FontStyle.Underline]: { textDecoration: "underline" }, -} - -function getStyle(token: IThemedToken) { - const fontStyle = token.fontStyle - ? FONT_STYLE_TO_CSS[token.fontStyle] - : {} - return { - color: token.color, - ...fontStyle, - } -} - -type ThemedCode = { - lines: IThemedToken[][] - fg: string - bg: string -} - -const newlineRe = /\r\n|\r|\n/ -export function tokenizePlaceholder( - code: string -): CodeLine[] { - const lines = code.split(newlineRe) - return lines.map(line => [[line, {}]]) -} - -export function getBasicThemedCode( - code: string, - theme: EditorTheme -): ThemedCode { - const lines = code.split(newlineRe) - const { fg, bg } = getThemeDefaultColors(theme) - return { - lines: lines.map(line => [{ content: line }]), - fg, - bg, - } -} diff --git a/packages/smooth-code/src/index.tsx b/packages/smooth-code/src/index.tsx index c8c26df6..65dc53e7 100644 --- a/packages/smooth-code/src/index.tsx +++ b/packages/smooth-code/src/index.tsx @@ -1,15 +1,9 @@ -import { HeavyCode, CodeProps } from "./heavy-code" import { CodeTween, CodeStep, CodeConfig, } from "./code-tween" -import { CodeAnnotation } from "./step-parser" -import { - highlightTween, - highlightCode, -} from "./highlighter" -import { Code } from "./oldcode" +import { CodeAnnotation } from "./partial-step-parser" import { CodeSpring } from "./code-spring" export { @@ -18,10 +12,4 @@ export { CodeAnnotation, CodeStep, CodeConfig, - // Deprecated: - HeavyCode, - Code, - CodeProps, - highlightCode, - highlightTween, } diff --git a/packages/smooth-code/src/line-elements.tsx b/packages/smooth-code/src/line-elements.tsx index b78aa54b..1131836c 100644 --- a/packages/smooth-code/src/line-elements.tsx +++ b/packages/smooth-code/src/line-elements.tsx @@ -1,8 +1,7 @@ -import React from "react" import { LineWithElement, AnnotatedLine, -} from "./step-parser" +} from "./partial-step-parser" import { map } from "@code-hike/utils" import { easing, stagger } from "./tween" diff --git a/packages/smooth-code/src/oldcode.tsx b/packages/smooth-code/src/oldcode.tsx deleted file mode 100644 index 030424ba..00000000 --- a/packages/smooth-code/src/oldcode.tsx +++ /dev/null @@ -1,152 +0,0 @@ -import React from "react" -import { useDimensions, Dimensions } from "./use-dimensions" -import { IRawTheme } from "vscode-textmate" -import { DEFAULT_THEME } from "./themes" -import { - Tween, - FullTween, - FocusString, -} from "@code-hike/utils" -import { - useStepParser, - CodeAnnotation, - CodeShift, -} from "./partial-step-parser" -import { SmoothLines } from "./smooth-lines" -import { getThemeDefaultColors } from "./themes" -import { HighlightedLine } from "./partial-step-parser" - -type HTMLProps = React.DetailedHTMLProps< - React.HTMLAttributes, - HTMLPreElement -> - -export type CodeProps = { - highlightedLines: FullTween - focus: Tween - progress: number - /* not really the height, when this changes we measure everything again */ - parentHeight?: any - minColumns?: number - minZoom?: number - maxZoom?: number - horizontalCenter?: boolean - theme?: IRawTheme - htmlProps?: HTMLProps - annotations?: Tween -} - -const DEFAULT_MIN_COLUMNS = 40 - -export function Code(props: CodeProps) { - const { - highlightedLines, - focus, - parentHeight, - htmlProps, - theme = (DEFAULT_THEME as unknown) as IRawTheme, - annotations, - minColumns = DEFAULT_MIN_COLUMNS, - } = props - - const stepInfo = useStepParser({ - highlightedLines, - theme, - focus, - annotations, - }) - - const { - element, - dimensions, - } = useDimensions(stepInfo.code, focus, minColumns, [ - parentHeight, - ]) - - return !dimensions ? ( - - ) : ( - - ) -} - -function BeforeDimensions({ - element, - htmlProps, -}: { - element: React.ReactNode - htmlProps?: HTMLProps -}) { - return ( - - {element} - - ) -} - -function AfterDimensions({ - progress, - minZoom = 0.5, - maxZoom = 1.5, - horizontalCenter = false, - htmlProps, - theme = (DEFAULT_THEME as unknown) as IRawTheme, - dimensions, - stepInfo, -}: CodeProps & { - dimensions: NonNullable - stepInfo: CodeShift -}) { - const { bg, fg } = getThemeDefaultColors(theme) - - return ( - - - - ) -} - -function Wrapper({ - htmlProps, - style, - children, -}: { - htmlProps?: HTMLProps - style: React.CSSProperties - children: React.ReactNode -}) { - return ( -
-      {children}
-    
- ) -} diff --git a/packages/smooth-code/src/smooth-container.tsx b/packages/smooth-code/src/smooth-container.tsx index 6bff6524..3aae15a9 100644 --- a/packages/smooth-code/src/smooth-container.tsx +++ b/packages/smooth-code/src/smooth-container.tsx @@ -1,6 +1,6 @@ import React from "react" import { map } from "@code-hike/utils" -import { CodeStep } from "./step-parser" +import { CodeShift } from "./partial-step-parser" import { Dimensions } from "./use-dimensions" import { tween, easing } from "./tween" @@ -17,7 +17,7 @@ export function SmoothContainer({ minZoom?: number maxZoom?: number center?: boolean - codeStep: CodeStep + codeStep: CodeShift children: (focusWidth: number) => React.ReactNode progress: number }) { @@ -152,7 +152,7 @@ function getTweenContentProps({ minZoom: number maxZoom: number horizontalCenter: boolean - codeStep: CodeStep + codeStep: CodeShift }) { const { lineHeight, lineWidth } = rest.dimensions! const paramTween = { diff --git a/packages/smooth-code/src/smooth-lines.tsx b/packages/smooth-code/src/smooth-lines.tsx index 836270d0..24024df3 100644 --- a/packages/smooth-code/src/smooth-lines.tsx +++ b/packages/smooth-code/src/smooth-lines.tsx @@ -1,9 +1,9 @@ import React from "react" import { Dimensions } from "./use-dimensions" import { - CodeStep, + CodeShift, AnnotatedTokenGroups, -} from "./step-parser" +} from "./partial-step-parser" import { SmoothContainer } from "./smooth-container" import { tween } from "./tween" import { FullTween, map, Tween } from "@code-hike/utils" @@ -14,7 +14,7 @@ type SmoothLinesProps = { minZoom?: number maxZoom?: number center?: boolean - codeStep: CodeStep + codeStep: CodeShift } export function SmoothLines(props: SmoothLinesProps) { @@ -38,7 +38,7 @@ function Lines({ focusWidth, lineHeight, }: { - codeStep: CodeStep + codeStep: CodeShift focusWidth: number lineHeight: number progress: number @@ -102,7 +102,7 @@ function Lines({ ) } -type CodeLine = CodeStep["groups"]["prev"][number]["lines"][number] +type CodeLine = CodeShift["groups"]["prev"][number]["lines"][number] function LineGroup({ lines, diff --git a/packages/smooth-code/src/splitter.tsx b/packages/smooth-code/src/splitter.tsx index 4b16e931..3db3ced5 100644 --- a/packages/smooth-code/src/splitter.tsx +++ b/packages/smooth-code/src/splitter.tsx @@ -18,7 +18,7 @@ import { AnnotatedLine, MultiLineAnnotation, InlineAnnotation, -} from "./step-parser" +} from "./partial-step-parser" import React from "react" export function splitByAnnotations( diff --git a/packages/smooth-code/src/step-parser.tsx b/packages/smooth-code/src/step-parser.tsx deleted file mode 100644 index 5e2ca3f4..00000000 --- a/packages/smooth-code/src/step-parser.tsx +++ /dev/null @@ -1,343 +0,0 @@ -import { - Tween, - mapWithDefault, - FocusString, - map, - FullTween, - withDefault, -} from "@code-hike/utils" -import { - isHighlighterReady, - loadHighlighter, - highlightOrPlaceholder, -} from "./highlighter" -import { EditorTheme } from "./themes" -import { mergeLines } from "./differ" -import { - splitByFocus, - splitByAnnotations, -} from "./splitter" -import { useAsyncMemo } from "./use-async-memo" -import React from "react" -import { TweenParams } from "./tween" -import { getLinesWithElements } from "./line-elements" -import { - parseAnnotations, - annotateInline, - annotateMultiline, -} from "./annotations" - -export type CodeAnnotation = { - focus: string - Component?: (props: { - style?: React.CSSProperties - children: React.ReactNode - data: any - theme: EditorTheme - }) => React.ReactElement - data?: any -} -type ParseInput = { - code: Tween - theme: EditorTheme - lang: string - focus: Tween - annotations?: Tween -} - -export function useStepParser(input: ParseInput) { - const { lang, theme, code, focus } = input - return useAsyncMemo( - { - isReady: isHighlighterReady(lang, theme), - load: () => loadHighlighter(lang, theme), - run: () => parse(input), - placeholder: () => parse(input), - }, - [ - code.prev, - code.next, - focus.prev, - focus.next, - lang, - theme, - ] - ) -} - -function parse({ - code, - theme, - lang, - focus, - annotations, -}: ParseInput) { - const normalCode = mapWithDefault(code, "", normalize) - - const highlightedLines = map(normalCode, code => - highlight({ code, theme, lang }) - ) - - const mergedCode = merge(normalCode, highlightedLines) - - const { - inlineAnnotations, - multilineAnnotations, - } = parseAllAnnotations(annotations, theme) - - const focusedCode = splitLinesByFocus( - mergedCode, - withDefault(focus, null), - inlineAnnotations - ) - - const annotatedCode = addAnnotations( - focusedCode, - inlineAnnotations, - multilineAnnotations - ) - - const codeStep = addExtraStuff(annotatedCode) - - console.log({ codeStep }) - - return codeStep -} - -// 0 - normalize - -function normalize(text: string | null | undefined) { - // TODO replace tabs with spaces? - return (text || "").trimEnd().concat("\n") -} - -// 1 - highlight - -type HighlightedToken = { - content: string - props: { style?: React.CSSProperties } -} - -export type HighlightedLine = { - tokens: HighlightedToken[] -} - -function highlight({ - code, - theme, - lang, -}: { - code: string - theme: EditorTheme - lang: string -}): HighlightedLine[] { - const lines = highlightOrPlaceholder(code, lang, theme) - return lines.map((line, i) => ({ - tokens: line.map(([content, props]) => ({ - content, - props, - })), - })) -} - -// 2 - merge lines - -type Movement = "enter" | "exit" | "stay" - -export type MergedLine = { - tokens: HighlightedToken[] - lineNumber: Tween - move: Movement - enterIndex: null | number - exitIndex: null | number -} - -export interface MergedCode { - lines: MergedLine[] - enterCount: number - exitCount: number -} - -function merge( - code: FullTween, - highlightedLines: FullTween -): MergedCode { - return mergeLines(code, highlightedLines) -} - -// 3 - parse annotationss - -export type MultiLineAnnotation = { - /* line numbers (starting at 1) */ - lineNumbers: { start: number; end: number } - data: any - theme: EditorTheme - Component: (props: { - style: React.CSSProperties - children: React.ReactNode - data: any - theme: EditorTheme - }) => React.ReactElement -} - -export type InlineAnnotation = { - /* column numbers (starting at 1) */ - columnNumbers: { start: number; end: number } - data: any - theme: EditorTheme - Component: (props: { - style?: React.CSSProperties - children: React.ReactNode - data: any - theme: EditorTheme - }) => React.ReactElement -} - -function parseAllAnnotations( - annotations: - | Tween - | undefined, - theme: EditorTheme -) { - return parseAnnotations(annotations, theme) -} - -// 4 - split lines by focus - -export type TokenGroup = { - tokens: HighlightedToken[] - focused: FullTween - element: React.ReactNode -} - -export interface FocusedLine - extends Omit { - groups: TokenGroup[] - lineNumber: Tween - focused: FullTween -} - -export interface FocusedCode - extends Omit { - lines: FocusedLine[] - firstFocusedLineNumber: FullTween - lastFocusedLineNumber: FullTween -} - -function splitLinesByFocus( - mergedCode: MergedCode, - focus: FullTween, - annotations: FullTween< - Record - > -): FocusedCode { - return splitByFocus(mergedCode, focus, annotations) -} - -// 5 - add annotations - -export type AnnotatedTokenGroups = { - groups: TokenGroup[] - annotation?: InlineAnnotation -} - -export interface AnnotatedLine - extends Omit { - annotatedGroups: Tween[] -} - -export type LineGroup = { - annotation?: MultiLineAnnotation - lines: AnnotatedLine[] -} -export interface AnnotatedCode - extends Omit { - lineGroups: FullTween - firstFocusedLineNumber: FullTween - lastFocusedLineNumber: FullTween - lineCount: FullTween -} - -function addAnnotations( - { lines, ...focusedCode }: FocusedCode, - inlineAnnotations: FullTween< - Record - >, - annotations: FullTween -): AnnotatedCode { - const annotatedLines = annotateInline( - lines, - inlineAnnotations - ) as AnnotatedLine[] - - const lineGroups = annotateMultiline( - annotatedLines, - annotations - ) - - return { - ...focusedCode, - lineGroups: lineGroups, - lineCount: { - prev: lines.filter(l => l.lineNumber.prev != null) - .length, - next: lines.filter(l => l.lineNumber.next != null) - .length, - }, - } -} - -// - add extra stuff - -export type LineWithElement = AnnotatedLine & { - key: number - tweenX: TweenParams - tweenY: TweenParams -} -type LineGroupWithElement = { - annotation?: MultiLineAnnotation - lines: LineWithElement[] -} - -export type CodeStep = { - groups: FullTween - firstFocusedLineNumber: FullTween - lastFocusedLineNumber: FullTween - verticalInterval: [number, number] - lineCount: FullTween -} - -function addExtraStuff(codeStep: AnnotatedCode): CodeStep { - const vInterval = verticalInterval( - codeStep.enterCount, - codeStep.exitCount - ) - - const newGroups = map(codeStep.lineGroups, groups => - groups.map(group => ({ - ...group, - lines: getLinesWithElements( - group.lines, - vInterval, - codeStep.enterCount, - codeStep.exitCount - ), - })) - ) - - return { - ...codeStep, - groups: newGroups, - verticalInterval: vInterval, - } -} - -function verticalInterval( - enterCount: number, - exitCount: number -): [number, number] { - if (enterCount <= 0 && exitCount <= 0) return [0, 1] - if (enterCount <= 0 && exitCount >= 1) return [0.33, 1] - if (enterCount >= 1 && exitCount <= 0) return [0, 0.67] - return [0.25, 0.75] -} diff --git a/packages/smooth-code/src/use-async-memo.ts b/packages/smooth-code/src/use-async-memo.ts deleted file mode 100644 index 672413b7..00000000 --- a/packages/smooth-code/src/use-async-memo.ts +++ /dev/null @@ -1,57 +0,0 @@ -import React from "react" - -type AsyncMemoOptions = { - isReady: boolean - load: () => Promise - run: () => T - placeholder: () => T -} - -export function useAsyncMemo( - { isReady, load, run, placeholder }: AsyncMemoOptions, - deps?: React.DependencyList -): T { - const [ - { - result: lastLoadedResult, - deps: lastLoadedDeps, - version, - }, - setState, - ] = React.useState<{ - result: T | null - deps: React.DependencyList | undefined - version: number - }>({ result: null, deps: [], version: 0 }) - - React.useEffect(() => { - if (!isReady) { - load().then(() => { - setState(({ version }) => ({ - result: run(), - deps, - version: version + 1, - })) - }) - } - }, deps) - - return React.useMemo(() => { - if (depsChanged(deps, lastLoadedDeps)) { - return isReady ? run() : placeholder() - } else { - return lastLoadedResult as T - } - }, [version, ...deps]) -} - -function depsChanged( - oldDeps: React.DependencyList | undefined, - newDeps: React.DependencyList | undefined -) { - if (oldDeps === newDeps) return false - if (!oldDeps || !newDeps) return true - return oldDeps?.some( - (dep, index) => newDeps[index] !== dep - ) -} diff --git a/packages/storybook/src/code-spring.story.js b/packages/storybook/src/code-spring.story.js index 36d155c5..90a2661b 100644 --- a/packages/storybook/src/code-spring.story.js +++ b/packages/storybook/src/code-spring.story.js @@ -36,8 +36,7 @@ const x = (y) => y++ `.trim() const prevAnnotations = [ - { focus: "1[10:11]" }, - { focus: "2[1:5]" }, + { focus: "1[10:11],2[1:5]" }, { focus: "3[8]" }, ] diff --git a/packages/utils/src/focus.ts b/packages/utils/src/focus.ts index af774c5f..4c30a1f1 100644 --- a/packages/utils/src/focus.ts +++ b/packages/utils/src/focus.ts @@ -34,7 +34,7 @@ export function mapFocusToLineNumbers( } } -function splitParts(focus: string) { +export function splitParts(focus: string) { return focus.split(/,(?![^\[]*\])/g) } diff --git a/yarn.lock b/yarn.lock index 4bc54991..7d53e61f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -14193,13 +14193,6 @@ onetime@^5.1.0, onetime@^5.1.2: dependencies: mimic-fn "^2.1.0" -onigasm@^2.2.5: - version "2.2.5" - resolved "https://registry.yarnpkg.com/onigasm/-/onigasm-2.2.5.tgz#cc4d2a79a0fa0b64caec1f4c7ea367585a676892" - integrity sha512-F+th54mPc0l1lp1ZcFMyL/jTs2Tlq4SqIHKIXGZOR/VkHkF9A7Fr5rRr5+ZG/lWeRsyrClLYRq7s/yFQ/XhWCA== - dependencies: - lru-cache "^5.1.1" - open@^7.0.2, open@^7.0.3: version "7.4.2" resolved "https://registry.yarnpkg.com/open/-/open-7.4.2.tgz#b8147e26dcf3e426316c730089fd71edd29c2321" @@ -16916,13 +16909,13 @@ shellwords@^0.1.1: resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b" integrity sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww== -shiki@^0.9.11: - version "0.9.11" - resolved "https://registry.yarnpkg.com/shiki/-/shiki-0.9.11.tgz#07d75dab2abb6dc12a01f79a397cb1c391fa22d8" - integrity sha512-tjruNTLFhU0hruCPoJP0y+B9LKOmcqUhTpxn7pcJB3fa+04gFChuEmxmrUfOJ7ZO6Jd+HwMnDHgY3lv3Tqonuw== +shiki@^0.9.14: + version "0.9.14" + resolved "https://registry.yarnpkg.com/shiki/-/shiki-0.9.14.tgz#6b3e369edf76049ae7ad7c2b0498c35c200b8dd7" + integrity sha512-uLHjjyJdNsMzF9GOF8vlOuZ8BwigiYPraMN5yjC826k8K7Xu90JQcC5GUNrzRibLgT2EOk9597I1IX+jRdA8nw== dependencies: jsonc-parser "^3.0.0" - onigasm "^2.2.5" + vscode-oniguruma "^1.6.1" vscode-textmate "5.2.0" side-channel@^1.0.4: @@ -18921,6 +18914,11 @@ vm-browserify@1.1.2, vm-browserify@^1.0.1: resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0" integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ== +vscode-oniguruma@^1.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/vscode-oniguruma/-/vscode-oniguruma-1.6.1.tgz#2bf4dfcfe3dd2e56eb549a3068c8ee39e6c30ce5" + integrity sha512-vc4WhSIaVpgJ0jJIejjYxPvURJavX6QG41vu0mGhqywMkQqulezEqEQ3cO3gc8GvcOpX6ycmKGqRoROEMBNXTQ== + vscode-textmate@5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-5.2.0.tgz#01f01760a391e8222fe4f33fbccbd1ad71aed74e"