Skip to content

Commit

Permalink
Fix widget issues (#7350)
Browse files Browse the repository at this point in the history
* Pass down ref

* Clean up dangling widgets, calculate line position better
  • Loading branch information
dem4ron authored Jan 21, 2025
1 parent a7ada7d commit 86d5d00
Show file tree
Hide file tree
Showing 7 changed files with 71 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,19 @@ export class AnimationTimeline {
: null
}

public frameAtTime(time: number) {
const reversedIndex = this.frames
.slice()
.reverse()
.findIndex((frame) => {
return frame.time <= time
})

const index = this.frames.length - 1 - reversedIndex

return this.frames[index]
}

public getProgress() {
return this.progress
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export class InformationWidget extends WidgetType {
private observer: MutationObserver | null = null
private autoUpdateCleanup: (() => void) | null = null
private scrollContainer: HTMLElement | null = null
private previousPosition: { x: number; y: number } | null = null

constructor(
private readonly tooltipHtml: string,
Expand Down Expand Up @@ -52,6 +53,7 @@ export class InformationWidget extends WidgetType {
private createTooltip() {
this.tooltip = document.createElement('div')
this.tooltip.classList.add('information-tooltip')

if (this.status === 'ERROR') {
this.tooltip.classList.add('error')
} else {
Expand All @@ -65,6 +67,18 @@ export class InformationWidget extends WidgetType {
this.tooltip.style.opacity = '0'
}

private cleanupDuplicateTooltips() {
const tooltips = document.querySelectorAll('.information-tooltip')

if (tooltips.length > 1) {
tooltips.forEach((tooltip, index) => {
if (index < tooltips.length - 1) {
tooltip.remove()
}
})
}
}

private applyHighlighting(element: HTMLElement) {
hljs.registerLanguage('javascript', javascript)
const codeBlocks = element.querySelectorAll('pre code')
Expand Down Expand Up @@ -104,6 +118,9 @@ export class InformationWidget extends WidgetType {
private positionTooltip() {
if (!this.referenceElement || !this.tooltip || !this.arrowElement) return
const editor = document.getElementById('bootcamp-cm-editor')

this.cleanupDuplicateTooltips()

computePosition(this.referenceElement, this.tooltip, {
placement: 'right',
middleware: [
Expand All @@ -112,6 +129,13 @@ export class InformationWidget extends WidgetType {
arrow({ element: this.arrowElement! }),
],
}).then(({ x, y, middlewareData }) => {
if (x !== 0) {
// ||= - initialise if doesn't exist
this.previousPosition ||= { x, y }
} else if (this.previousPosition?.x) {
x = this.previousPosition.x
}

const { arrow } = middlewareData
if (!this.tooltip) return
Object.assign(this.tooltip.style, {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import { EditorView } from '@codemirror/view'

export function scrollToLine(view: EditorView, line: number): void {
export function scrollToLine(view: EditorView | null, line: number): void {
if (!view) return
const doc = view.state.doc
const linePos = doc.line(line)
if (linePos) {
view.dispatch({
effects: EditorView.scrollIntoView(linePos.from, { y: 'center' }),
})
const lineBlock = view.lineBlockAt(linePos.from)
if (lineBlock) {
const viewportHeight = view.scrollDOM.clientHeight
const blockHeight = lineBlock.bottom - lineBlock.top

const centeredTop = lineBlock.top - viewportHeight / 2 + blockHeight / 2

view.scrollDOM.scrollTo({ top: centeredTop })
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react'
import { useEffect, useState } from 'react'
import { useState } from 'react'
import { calculateMaxInputValue, useScrubber } from './useScrubber'
import useEditorStore from '@/components/bootcamp/SolveExercisePage/store/editorStore'
import { InformationWidgetToggleButton } from './InformationWidgetToggleButton'
Expand All @@ -15,7 +15,7 @@ function Scrubber({
animationTimeline: AnimationTimeline | undefined | null
frames: Frame[]
}) {
const [isPlaying, setIsPlaying] = useState(false)
const [_, setIsPlaying] = useState(false)

const { hasCodeBeenEdited, setShouldShowInformationWidget } = useEditorStore()

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { AnimeInstance } from 'animejs'
import { useState, useEffect, useCallback, useRef } from 'react'
import { useState, useEffect, useCallback, useRef, useContext } from 'react'
import anime from 'animejs'
import useEditorStore from '../store/editorStore'
import type { AnimationTimeline } from '../AnimationTimeline/AnimationTimeline'
Expand All @@ -10,6 +10,8 @@ import { INFO_HIGHLIGHT_COLOR } from '../CodeMirror/extensions/lineHighlighter'
import { scrollToHighlightedLine } from './scrollToHighlightedLine'
import useAnimationTimelineStore from '../store/animationTimelineStore'
import useTestStore from '../store/testStore'
import { SolveExercisePageContext } from '../SolveExercisePageContextWrapper'
import { scrollToLine } from '../CodeMirror/scrollToLine'

const FRAME_DURATION = 50

Expand All @@ -32,6 +34,8 @@ export function useScrubber({
setUnderlineRange,
} = useEditorStore()

const { editorView } = useContext(SolveExercisePageContext)

const { setIsTimelineComplete } = useAnimationTimelineStore()

// this effect is responsible for updating the scrubber value based on the current time of animationTimeline
Expand Down Expand Up @@ -127,12 +131,17 @@ export function useScrubber({
if (animationTimeline) {
animationTimeline.pause()
animationTimeline.seek(newValue)
const line = animationTimeline.currentFrame?.line

if (line) {
scrollToLine(editorView, line)
}
} else {
const validIndex = Math.max(0, newValue)
const highlightedLine = newValue === -1 ? 0 : frames[validIndex].line
setHighlightedLine(highlightedLine)
scrollToLine(editorView, highlightedLine)
}
scrollToHighlightedLine()
},
[setValue, setInformationWidgetData]
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,14 @@ export default function SolveExercisePage({

return (
<SolveExercisePageContextWrapper
value={{ links, solution, exercise, code, resetEditorToStub }}
value={{
links,
solution,
exercise,
code,
resetEditorToStub,
editorView: editorViewRef.current,
}}
>
<div id="bootcamp-solve-exercise-page">
<Header />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { EditorView } from '@codemirror/view'
import React from 'react'

import { createContext } from 'react'

type SolveExercisePageContextValues = Pick<
SolveExercisePageProps,
'links' | 'solution' | 'exercise' | 'code'
> & { resetEditorToStub: () => void }
> & { resetEditorToStub: () => void; editorView: EditorView | null }

export const SolveExercisePageContext =
createContext<SolveExercisePageContextValues>({
Expand All @@ -14,6 +15,7 @@ export const SolveExercisePageContext =
exercise: {} as SolveExercisePageContextValues['exercise'],
code: {} as SolveExercisePageContextValues['code'],
resetEditorToStub: () => {},
editorView: {} as EditorView | null,
})

export default function SolveExercisePageContextWrapper({
Expand Down

0 comments on commit 86d5d00

Please sign in to comment.