11import { useCallback , useEffect , useMemo , useState } from 'react' ;
22import { normalizeMenuSize , VALID_CHEST_SIZES } from '../../editor/config' ;
3- import { itemsAtTick , TICK_MS } from '../../editor/animation' ;
3+ import { canvasItems , slotAnimations , TICK_MS } from '../../editor/animation' ;
44import { applyVisualEdit , readVisual } from '../../editor/yamlDocument' ;
55import { ItemEditor } from './ItemEditor' ;
66import { ItemPalette } from './ItemPalette' ;
77import { MenuCanvas } from './MenuCanvas' ;
88import { SlotContextMenu , type SlotMenuTarget } from './SlotContextMenu' ;
9+ import { ResizeHandle } from '../ResizeHandle' ;
10+ import { usePanelWidth } from '../../editor/panelWidth' ;
911import { MenuSettings } from './MenuSettings' ;
1012import { AnimationEditor } from './AnimationEditor' ;
1113import { GlobalTimeline } from './GlobalTimeline' ;
@@ -30,7 +32,7 @@ export function VisualEditor({ source, platform, serverVersion, onChange }: Visu
3032 // Copied items live for the session, so one can be pasted across menus.
3133 const [ clipboard , setClipboard ] = useState < VisualItem | null > ( null ) ;
3234 const [ panel , setPanel ] = useState < PanelKey > ( 'palette' ) ;
33- const playback = usePlayback ( ) ;
35+ const [ panelWidth , setPanelWidth ] = usePanelWidth ( 'visual-panel' , 350 ) ;
3436
3537 const parsed = useMemo ( ( ) => {
3638 try {
@@ -40,6 +42,8 @@ export function VisualEditor({ source, platform, serverVersion, onChange }: Visu
4042 }
4143 } , [ source , platform ] ) ;
4244
45+ const playback = usePlayback ( parsed . menu !== null && slotAnimations ( parsed . menu ) . length > 0 ) ;
46+
4347 if ( parsed . menu === null ) {
4448 return (
4549 < div className = "visual-editor-container" >
@@ -99,7 +103,7 @@ export function VisualEditor({ source, platform, serverVersion, onChange }: Visu
99103
100104 < MenuCanvas
101105 size = { normalizeMenuSize ( menu . size ) }
102- items = { playback . playing ? itemsAtTick ( menu , playback . tick ) : menu . items }
106+ items = { canvasItems ( menu , playback . tick , playback . playing ) }
103107 selectedSlot = { selectedSlot }
104108 serverVersion = { serverVersion }
105109 onSelect = { slot => {
@@ -134,7 +138,9 @@ export function VisualEditor({ source, platform, serverVersion, onChange }: Visu
134138 < GlobalTimeline menu = { menu } serverVersion = { serverVersion } playback = { playback } />
135139 </ div >
136140
137- < div className = "visual-editor-right-panel" >
141+ < div className = "visual-editor-right-panel" style = { { width : `${ panelWidth } px` } } >
142+ < ResizeHandle edge = "left" width = { panelWidth } min = { 250 } max = { 600 } onResize = { setPanelWidth } />
143+
138144 < div className = "visual-editor-tabs" >
139145 { PANELS . map ( tab => (
140146 < button
@@ -236,10 +242,21 @@ export interface Playback {
236242 * Drives every animation of the menu off one tick counter, so two animations
237243 * with different intervals stay in step exactly as they do in game.
238244 */
239- function usePlayback ( ) : Playback {
245+ function usePlayback ( hasAnimations : boolean ) : Playback {
240246 const [ playing , setPlaying ] = useState ( false ) ;
241247 const [ tick , setTick ] = useState ( 0 ) ;
242248
249+ // The menu animates on its own once it loads, the way it does in game.
250+ useEffect ( ( ) => {
251+ if ( ! hasAnimations ) {
252+ return ;
253+ }
254+
255+ const start = setTimeout ( ( ) => setPlaying ( true ) , 500 ) ;
256+
257+ return ( ) => clearTimeout ( start ) ;
258+ } , [ hasAnimations ] ) ;
259+
243260 useEffect ( ( ) => {
244261 if ( ! playing ) {
245262 return ;
0 commit comments