11'use client'
22
3- import React , { useCallback , useEffect , useMemo , useRef , useState } from 'react'
3+ import React , { useCallback , useEffect , useLayoutEffect , useMemo , useRef , useState } from 'react'
44import { Label , Switch } from '@/components/emcn'
55import { isApiClientError } from '@/lib/api/client/errors'
66import { requestJson } from '@/lib/api/client/request'
@@ -50,6 +50,8 @@ export function ChunkEditor({
5050 onCreated,
5151} : ChunkEditorProps ) {
5252 const textareaRef = useRef < HTMLTextAreaElement > ( null )
53+ const tokenizedScrollRef = useRef < HTMLDivElement > ( null )
54+ const preservedScrollTopRef = useRef ( 0 )
5355 const { mutateAsync : updateChunk } = useUpdateChunk ( )
5456 const { mutateAsync : createChunk } = useCreateChunk ( )
5557
@@ -170,6 +172,20 @@ export function ChunkEditor({
170172 [ saveRef ]
171173 )
172174
175+ const handleTokenizerChange = useCallback (
176+ ( value : boolean ) => {
177+ const source = tokenizerOn ? tokenizedScrollRef . current : textareaRef . current
178+ preservedScrollTopRef . current = source ?. scrollTop ?? 0
179+ setTokenizerOn ( value )
180+ } ,
181+ [ tokenizerOn ]
182+ )
183+
184+ useLayoutEffect ( ( ) => {
185+ const target = tokenizerOn ? tokenizedScrollRef . current : textareaRef . current
186+ if ( target ) target . scrollTop = preservedScrollTopRef . current
187+ } , [ tokenizerOn ] )
188+
173189 const tokenStrings = useMemo ( ( ) => {
174190 if ( ! tokenizerOn || ! editedContent ) return [ ]
175191 return getTokenStrings ( editedContent )
@@ -196,7 +212,10 @@ export function ChunkEditor({
196212 } }
197213 >
198214 { tokenizerOn ? (
199- < div className = 'h-full w-full cursor-default overflow-y-auto whitespace-pre-wrap break-words p-6 font-sans text-[var(--text-body)] text-sm' >
215+ < div
216+ ref = { tokenizedScrollRef }
217+ className = 'h-full w-full cursor-default overflow-y-auto whitespace-pre-wrap break-words p-6 font-sans text-[var(--text-body)] text-sm'
218+ >
200219 { tokenStrings . map ( ( token , index ) => (
201220 < span
202221 key = { index }
@@ -232,7 +251,7 @@ export function ChunkEditor({
232251 < div className = 'flex items-center justify-between border-[var(--border)] border-t px-6 py-2.5' >
233252 < TokenizerToggle
234253 checked = { tokenizerOn }
235- onCheckedChange = { setTokenizerOn }
254+ onCheckedChange = { handleTokenizerChange }
236255 hoveredTokenIndex = { tokenizerOn ? hoveredTokenIndex : null }
237256 />
238257 < span className = 'text-[var(--text-secondary)] text-caption' >
0 commit comments