Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 207x 207x 207x 207x 207x 207x 207x 207x 207x 207x 207x 207x 207x 207x 165x 165x 165x 165x 165x 165x 165x 165x 165x 207x 207x 207x 207x 207x 1x 1x 180x 180x 180x 180x | 'use client'
import type React from 'react'
import { createContext, useContext, useMemo, useState } from 'react'
import type { PedagogicalSegment } from './DecompositionWithReasons'
type HintFocus = 'none' | 'term' | 'bead'
interface TutorialUIState {
showCoachBar: boolean
setShowCoachBar: (v: boolean) => void
canHideCoachBar: boolean
// Single-owner tooltip gate (tutorial-only)
hintFocus: HintFocus
requestFocus: (who: HintFocus) => boolean // returns true if granted
releaseFocus: (who: HintFocus) => void
// Currently active segment for Coach Bar
activeSegment: PedagogicalSegment | null
setActiveSegment: (seg: PedagogicalSegment | null) => void
}
const TutorialUIContext = createContext<TutorialUIState | undefined>(undefined)
export function TutorialUIProvider({
children,
initialSegment = null,
canHideCoachBar = true,
}: {
children: React.ReactNode
initialSegment?: PedagogicalSegment | null
canHideCoachBar?: boolean
}) {
const [showCoachBar, setShowCoachBar] = useState(true)
const [hintFocus, setHintFocus] = useState<HintFocus>('none')
const [activeSegment, setActiveSegment] = useState<PedagogicalSegment | null>(initialSegment)
const value: TutorialUIState = useMemo(
() => ({
showCoachBar,
setShowCoachBar,
canHideCoachBar,
hintFocus,
requestFocus: (who: HintFocus) => {
if (hintFocus === 'none' || hintFocus === who) {
setHintFocus(who)
return true
}
if (process.env.NODE_ENV !== 'production') {
console.debug(`[tutorial-ui] focus denied: ${who}, owned by ${hintFocus}`)
}
return false
},
releaseFocus: (who: HintFocus) => {
if (hintFocus === who) setHintFocus('none')
},
activeSegment,
setActiveSegment,
}),
[showCoachBar, canHideCoachBar, hintFocus, activeSegment]
)
return <TutorialUIContext.Provider value={value}>{children}</TutorialUIContext.Provider>
}
export function useTutorialUI(): TutorialUIState {
const ctx = useContext(TutorialUIContext)
if (!ctx) {
throw new Error('useTutorialUI must be used within <TutorialUIProvider> (tutorial routes)')
}
return ctx
}
|