@@ -16,6 +16,7 @@ export default function CanvasPanel({ artifacts, selectedId, onSelect, onClose }
1616 const [ width , setWidth ] = useState ( ( ) => {
1717 try { const v = localStorage . getItem ( WIDTH_KEY ) ; return v ? Number ( v ) : null } catch { return null }
1818 } )
19+ const [ fullscreen , setFullscreen ] = useState ( false )
1920 const codeRef = useRef ( null )
2021 const panelRef = useRef ( null )
2122
@@ -149,33 +150,65 @@ export default function CanvasPanel({ artifacts, selectedId, onSelect, onClose }
149150 }
150151
151152 return (
152- < div className = "canvas-panel" ref = { panelRef } style = { width ? { width : `${ width } px` , maxWidth : 'none' } : undefined } >
153- < div
154- className = "canvas-resize-handle"
155- onMouseDown = { startResize }
156- onDoubleClick = { resetWidth }
157- role = "separator"
158- aria-orientation = "vertical"
159- aria-label = "Resize canvas (double-click to reset)"
160- title = "Drag to resize, double-click to reset"
161- />
153+ < div
154+ className = { `canvas-panel${ fullscreen ? ' canvas-panel--fullscreen' : '' } ` }
155+ ref = { panelRef }
156+ style = { ! fullscreen && width ? { width : `${ width } px` , maxWidth : 'none' } : undefined }
157+ >
158+ { ! fullscreen && (
159+ < div
160+ className = "canvas-resize-handle"
161+ onMouseDown = { startResize }
162+ onDoubleClick = { resetWidth }
163+ role = "separator"
164+ aria-orientation = "vertical"
165+ aria-label = "Resize canvas (double-click to reset)"
166+ title = "Drag to resize, double-click to reset"
167+ />
168+ ) }
162169 < div className = "canvas-panel-header" >
163170 < span className = "canvas-panel-title" > { current . title || 'Artifact' } </ span >
164- < button className = "btn btn-secondary btn-sm" onClick = { onClose } title = "Close canvas" >
165- < i className = "fas fa-times" />
166- </ button >
171+ < div className = "canvas-header-actions" >
172+ < button
173+ className = "btn btn-secondary btn-sm"
174+ onClick = { ( ) => setFullscreen ( f => ! f ) }
175+ title = { fullscreen ? 'Exit fullscreen' : 'Fullscreen' }
176+ aria-label = { fullscreen ? 'Exit fullscreen' : 'Fullscreen' }
177+ >
178+ < i className = { `fas ${ fullscreen ? 'fa-compress' : 'fa-expand' } ` } aria-hidden = "true" />
179+ </ button >
180+ < button className = "btn btn-secondary btn-sm" onClick = { onClose } title = "Close canvas" aria-label = "Close canvas" >
181+ < i className = "fas fa-times" aria-hidden = "true" />
182+ </ button >
183+ </ div >
167184 </ div >
168185
169186 { artifacts . length > 1 && (
170- < div className = "canvas-panel-tabs" >
187+ < div
188+ className = "canvas-panel-tabs"
189+ role = "tablist"
190+ aria-label = "Artifacts"
191+ onKeyDown = { ( e ) => {
192+ if ( e . key !== 'ArrowRight' && e . key !== 'ArrowLeft' ) return
193+ e . preventDefault ( )
194+ const idx = artifacts . findIndex ( a => a . id === current . id )
195+ const n = e . key === 'ArrowRight'
196+ ? ( idx + 1 ) % artifacts . length
197+ : ( idx - 1 + artifacts . length ) % artifacts . length
198+ onSelect ( artifacts [ n ] . id )
199+ } }
200+ >
171201 { artifacts . map ( a => (
172202 < button
173203 key = { a . id }
204+ role = "tab"
205+ aria-selected = { a . id === current . id }
206+ tabIndex = { a . id === current . id ? 0 : - 1 }
174207 className = { `canvas-panel-tab${ a . id === ( current ?. id ) ? ' active' : '' } ` }
175208 onClick = { ( ) => onSelect ( a . id ) }
176209 title = { a . title }
177210 >
178- < i className = { `fas ${ getArtifactIcon ( a . type , a . language ) } ` } />
211+ < i className = { `fas ${ getArtifactIcon ( a . type , a . language ) } ` } aria-hidden = "true" />
179212 < span > { a . title } </ span >
180213 </ button >
181214 ) ) }
0 commit comments