@@ -135,7 +135,32 @@ function App() {
135135 if ( ! handle ) return
136136
137137 const minLeft = 240 // px
138- const maxLeft = Math . max ( 480 , Math . floor ( ( appEl . clientWidth - 100 ) * 0.85 ) )
138+ const computeMaxLeft = ( ) => Math . max ( 480 , Math . floor ( ( appEl . clientWidth - 100 ) * 0.85 ) )
139+ let maxLeft = computeMaxLeft ( )
140+
141+ // ARIA setup for accessibility
142+ try {
143+ handle . setAttribute ( 'role' , 'separator' )
144+ handle . setAttribute ( 'aria-orientation' , 'vertical' )
145+ handle . setAttribute ( 'aria-valuemin' , String ( minLeft ) )
146+ handle . setAttribute ( 'aria-valuemax' , String ( maxLeft ) )
147+ ; ( handle as HTMLElement ) . tabIndex = 0
148+ const current = Number ( ( getComputedStyle ( appEl ) . getPropertyValue ( '--left-col' ) || '' ) . replace ( 'px' , '' ) ) || minLeft
149+ handle . setAttribute ( 'aria-valuenow' , String ( current ) )
150+ handle . setAttribute ( 'aria-label' , 'Resize panels' )
151+ } catch { }
152+
153+ const applyLeft = ( px : number ) => {
154+ const clamped = Math . min ( Math . max ( px , minLeft ) , maxLeft )
155+ appEl . style . setProperty ( '--left-col' , `${ clamped } px` )
156+ try {
157+ localStorage . setItem ( 'gc.leftCol' , String ( clamped ) )
158+ } catch ( e ) {
159+ logError ( 'leftColSave' , e )
160+ }
161+ try { handle . setAttribute ( 'aria-valuenow' , String ( clamped ) ) } catch { }
162+ }
163+
139164 let dragging = false
140165
141166 const onPointerDown = ( e : PointerEvent ) => {
@@ -149,26 +174,60 @@ function App() {
149174 const rect = appEl . getBoundingClientRect ( )
150175 const x = e . clientX - rect . left
151176 const clamped = Math . min ( Math . max ( x - 12 , minLeft ) , maxLeft )
152- appEl . style . setProperty ( '--left-col' , `${ clamped } px` )
153- try {
154- localStorage . setItem ( 'gc.leftCol' , String ( clamped ) )
155- } catch ( e ) {
156- logError ( 'leftColSave' , e )
157- }
177+ applyLeft ( clamped )
158178 }
159179 const onPointerUp = ( e : PointerEvent ) => {
160180 dragging = false
161181 appEl . classList . remove ( 'resizing' )
162182 ; ( e . target as HTMLElement ) . releasePointerCapture ?.( e . pointerId )
163183 }
164184
185+ // Keyboard support: ArrowLeft/Right, Home/End
186+ const onKeyDown = ( e : KeyboardEvent ) => {
187+ const step = e . ctrlKey ? 50 : 16
188+ const curr = Number ( ( getComputedStyle ( appEl ) . getPropertyValue ( '--left-col' ) || '' ) . replace ( 'px' , '' ) ) || minLeft
189+ switch ( e . key ) {
190+ case 'ArrowLeft' :
191+ applyLeft ( curr - step )
192+ e . preventDefault ( )
193+ break
194+ case 'ArrowRight' :
195+ applyLeft ( curr + step )
196+ e . preventDefault ( )
197+ break
198+ case 'Home' :
199+ applyLeft ( minLeft )
200+ e . preventDefault ( )
201+ break
202+ case 'End' :
203+ applyLeft ( maxLeft )
204+ e . preventDefault ( )
205+ break
206+ }
207+ }
208+
209+ // Clamp saved width on window resize so layout never overflows
210+ const onWindowResize = ( ) => {
211+ const nextMax = computeMaxLeft ( )
212+ if ( nextMax !== maxLeft ) {
213+ maxLeft = nextMax
214+ try { handle . setAttribute ( 'aria-valuemax' , String ( maxLeft ) ) } catch { }
215+ const curr = Number ( ( getComputedStyle ( appEl ) . getPropertyValue ( '--left-col' ) || '' ) . replace ( 'px' , '' ) ) || minLeft
216+ applyLeft ( curr ) // re-clamp
217+ }
218+ }
219+
165220 handle . addEventListener ( 'pointerdown' , onPointerDown )
221+ handle . addEventListener ( 'keydown' , onKeyDown )
166222 window . addEventListener ( 'pointermove' , onPointerMove )
167223 window . addEventListener ( 'pointerup' , onPointerUp )
224+ window . addEventListener ( 'resize' , onWindowResize )
168225 return ( ) => {
169226 handle . removeEventListener ( 'pointerdown' , onPointerDown )
227+ handle . removeEventListener ( 'keydown' , onKeyDown )
170228 window . removeEventListener ( 'pointermove' , onPointerMove )
171229 window . removeEventListener ( 'pointerup' , onPointerUp )
230+ window . removeEventListener ( 'resize' , onWindowResize )
172231 }
173232 } , [ uiHasResizer ] )
174233
@@ -859,7 +918,14 @@ function App() {
859918 </ div >
860919
861920 { /* Resizer handle between columns */ }
862- < div className = "column-resizer" id = "gc-col-resizer" />
921+ < div
922+ className = "column-resizer"
923+ id = "gc-col-resizer"
924+ role = "separator"
925+ aria-orientation = "vertical"
926+ aria-label = "Resize panels"
927+ tabIndex = { 0 }
928+ />
863929
864930 < div className = "right-panel" >
865931 < div className = "panel-section" >
0 commit comments