@@ -7,7 +7,6 @@ import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react';
77import { ParseError , parseDeck } from '@/ir/parse' ;
88import { planDeck } from '@/ir/plan' ;
99import { reorderSlide } from '@/ir/source-edit' ;
10- import { replaceHeadingOccurrence , type EditableKind } from '@/ir/text-edit' ;
1110import { lintColors } from '@/render/lint' ;
1211import { resolveTheme } from '@/render/theme-resolver' ;
1312import type { Brand , Deck , Density , Mode , ThemeRef } from '@/ir/schema' ;
@@ -184,10 +183,6 @@ export function Editor({ deckId }: Props) {
184183 setSelectedSlide ( to ) ;
185184 } , [ ] ) ;
186185
187- const handleHeadingEdit = useCallback ( ( kind : EditableKind , index : number , nextText : string ) => {
188- setSource ( ( s ) => replaceHeadingOccurrence ( s , kind , index , nextText ) ) ;
189- } , [ ] ) ;
190-
191186 const handleInsert = useCallback ( ( snippet : string ) => {
192187 insertRef . current ?.( snippet ) ;
193188 } , [ ] ) ;
@@ -358,7 +353,6 @@ export function Editor({ deckId }: Props) {
358353 selectedSlide = { selectedSlide }
359354 onSelectSlide = { handleSelectSlide }
360355 onReorderSlide = { handleReorderSlide }
361- onHeadingEdit = { handleHeadingEdit }
362356 />
363357 ) : (
364358 < div className = "editor__error" >
@@ -471,13 +465,11 @@ function PreviewStage({
471465 selectedSlide,
472466 onSelectSlide,
473467 onReorderSlide,
474- onHeadingEdit,
475468} : {
476469 deck : Deck ;
477470 selectedSlide : number ;
478471 onSelectSlide : ( i : number ) => void ;
479472 onReorderSlide : ( from : number , to : number ) => void ;
480- onHeadingEdit : ( kind : EditableKind , index : number , nextText : string ) => void ;
481473} ) {
482474 const total = deck . slides . length ;
483475 const safeIndex = Math . min ( Math . max ( selectedSlide , 0 ) , Math . max ( total - 1 , 0 ) ) ;
@@ -502,88 +494,10 @@ function PreviewStage({
502494 return ( ) => window . removeEventListener ( 'keydown' , onKey ) ;
503495 } , [ safeIndex , total , onSelectSlide ] ) ;
504496
505- const slideRef = useRef < HTMLDivElement > ( null ) ;
506-
507- const beginEdit = useCallback (
508- ( el : HTMLElement ) => {
509- const tag = el . tagName . toLowerCase ( ) ;
510- if ( ! / ^ h [ 1 - 4 ] $ / . test ( tag ) ) return ;
511- // Compute occurrence index across the FULL deck, not just the visible
512- // slide. We render slides individually, so we have to look through deck.
513- const kind = tag as EditableKind ;
514- const targetText = el . textContent ?? '' ;
515- let occurrence = 0 ;
516- const targetLevel = Number ( kind . slice ( 1 ) ) ;
517- outer: for ( let s = 0 ; s < deck . slides . length ; s ++ ) {
518- const blocks = deck . slides [ s ] . blocks ;
519- const stack : typeof blocks = [ ...blocks ] ;
520- while ( stack . length > 0 ) {
521- const b = stack . shift ( ) ! ;
522- if ( b . type === 'heading' ) {
523- if ( b . level === targetLevel ) {
524- if ( s === safeIndex && b . text === targetText ) {
525- break outer;
526- }
527- occurrence ++ ;
528- }
529- } else if ( b . type === 'box' ) {
530- stack . unshift ( ...b . children ) ;
531- } else if ( b . type === 'columns' ) {
532- stack . unshift ( ...b . columns . flat ( ) ) ;
533- } else if ( b . type === 'grid' || b . type === 'cell' ) {
534- stack . unshift ( ...b . children ) ;
535- }
536- }
537- }
538- el . contentEditable = 'true' ;
539- el . classList . add ( 'preview-editable' ) ;
540- el . focus ( ) ;
541- const range = document . createRange ( ) ;
542- range . selectNodeContents ( el ) ;
543- const sel = window . getSelection ( ) ;
544- sel ?. removeAllRanges ( ) ;
545- sel ?. addRange ( range ) ;
546-
547- const finish = ( ) => {
548- el . removeEventListener ( 'blur' , finish ) ;
549- el . removeEventListener ( 'keydown' , onKey ) ;
550- el . contentEditable = 'false' ;
551- el . classList . remove ( 'preview-editable' ) ;
552- const next = ( el . textContent ?? '' ) . trim ( ) ;
553- if ( next && next !== targetText ) onHeadingEdit ( kind , occurrence , next ) ;
554- } ;
555- const onKey = ( ke : KeyboardEvent ) => {
556- if ( ke . key === 'Enter' && ! ke . shiftKey ) {
557- ke . preventDefault ( ) ;
558- el . blur ( ) ;
559- } else if ( ke . key === 'Escape' ) {
560- ke . preventDefault ( ) ;
561- el . textContent = targetText ;
562- el . blur ( ) ;
563- }
564- } ;
565- el . addEventListener ( 'blur' , finish ) ;
566- el . addEventListener ( 'keydown' , onKey ) ;
567- } ,
568- [ deck , safeIndex , onHeadingEdit ] ,
569- ) ;
570-
571- const onDoubleClick = useCallback (
572- ( e : React . MouseEvent < HTMLDivElement > ) => {
573- const t = e . target as HTMLElement ;
574- const heading = t . closest ( 'h1, h2, h3, h4' ) as HTMLElement | null ;
575- if ( heading && slideRef . current ?. contains ( heading ) ) {
576- e . preventDefault ( ) ;
577- beginEdit ( heading ) ;
578- }
579- } ,
580- [ beginEdit ] ,
581- ) ;
582-
583497 return (
584498 < div className = "stage" >
585499 < div className = "stage__viewport" >
586- < div className = "stage__slide" ref = { slideRef } onDoubleClick = { onDoubleClick } >
500+ < div className = "stage__slide" >
587501 < DeckRenderer deck = { visibleDeck } />
588502 </ div >
589503 </ div >
0 commit comments