@@ -22,19 +22,22 @@ interface SectionRegion {
22
22
id : any // this matches a grist document view section id
23
23
}
24
24
type Region = PanelRegion | SectionRegion ;
25
- type UpdateInitiator = { type : 'cycle' } | { type : 'mouse' , event ?: MouseEvent } ;
25
+ type StateUpdateInitiator = { type : 'cycle' } | { type : 'mouse' , event ?: MouseEvent } ;
26
+ interface State {
27
+ region ?: Region ;
28
+ initiator ?: StateUpdateInitiator ;
29
+ }
26
30
27
31
/**
28
32
* RegionFocusSwitcher enables keyboard navigation between app panels and doc widgets.
29
33
*
30
34
* It also follow mouse clicks to focus panels accordingly.
31
35
*/
32
36
export class RegionFocusSwitcher extends Disposable {
33
- // Currently focused region
34
- public readonly current : Observable < Region | undefined > ;
37
+ // State with currently focused region
38
+ private readonly _state : Observable < State > ;
35
39
36
40
private _gristDocObs : Observable < GristDoc | null > ;
37
- private _currentUpdateInitiator ?: UpdateInitiator ;
38
41
// Previously focused elements for each panel (not used for view section ids)
39
42
private _prevFocusedElements : Record < Panel , Element | null > = {
40
43
left : null ,
@@ -48,7 +51,10 @@ export class RegionFocusSwitcher extends Disposable {
48
51
49
52
constructor ( private _app : App ) {
50
53
super ( ) ;
51
- this . current = Observable . create ( this , undefined ) ;
54
+ this . _state = Observable . create ( this , {
55
+ region : undefined ,
56
+ initiator : undefined ,
57
+ } ) ;
52
58
this . _initiated = Observable . create ( this , false ) ;
53
59
}
54
60
@@ -82,7 +88,7 @@ export class RegionFocusSwitcher extends Disposable {
82
88
cancel : this . _onEscapeKeypress . bind ( this ) ,
83
89
} , this , true ) ) ;
84
90
85
- this . autoDispose ( this . current . addListener ( this . _onCurrentUpdate . bind ( this ) ) ) ;
91
+ this . autoDispose ( this . _state . addListener ( this . _onStateChange . bind ( this ) ) ) ;
86
92
87
93
const focusActiveSection = ( ) => this . focusActiveSection ( ) ;
88
94
this . _app . on ( 'clipboard_focus' , focusActiveSection ) ;
@@ -99,7 +105,7 @@ export class RegionFocusSwitcher extends Disposable {
99
105
100
106
public focusRegion (
101
107
region : Region | undefined ,
102
- options : { initiator ?: UpdateInitiator } = { }
108
+ options : { initiator ?: StateUpdateInitiator } = { }
103
109
) {
104
110
if ( region ?. type === 'panel' && ! getPanelElement ( region . id ) ) {
105
111
return ;
@@ -113,8 +119,7 @@ export class RegionFocusSwitcher extends Disposable {
113
119
throw new Error ( 'view section id is not supported when no view layout is rendered' ) ;
114
120
}
115
121
116
- this . _currentUpdateInitiator = options . initiator ;
117
- this . current . set ( region ) ;
122
+ this . _state . set ( { region, initiator : options . initiator } ) ;
118
123
}
119
124
120
125
public focusActiveSection ( ) {
@@ -124,7 +129,7 @@ export class RegionFocusSwitcher extends Disposable {
124
129
}
125
130
}
126
131
127
- public reset ( initiator ?: UpdateInitiator ) {
132
+ public reset ( initiator ?: StateUpdateInitiator ) {
128
133
this . focusRegion ( undefined , { initiator} ) ;
129
134
}
130
135
@@ -155,7 +160,7 @@ export class RegionFocusSwitcher extends Disposable {
155
160
if ( ! gristDoc ) {
156
161
return true ;
157
162
}
158
- const current = use ( this . current ) ;
163
+ const current = use ( this . _state ) . region ;
159
164
// on a grist doc, panel content is focusable only if it's the current region
160
165
if ( current ?. type === 'panel' && current . id === id ) {
161
166
return true ;
@@ -186,8 +191,8 @@ export class RegionFocusSwitcher extends Disposable {
186
191
} ) ,
187
192
dom . cls ( `${ cssFocusedPanel . className } -focused` , use => {
188
193
use ( this . _initiated ) ;
189
- const current = use ( this . current ) ;
190
- return this . _currentUpdateInitiator ?. type === 'cycle' && current ?. type === 'panel' && current . id === id ;
194
+ const current = use ( this . _state ) ;
195
+ return current . initiator ?. type === 'cycle' && current . region ?. type === 'panel' && current . region . id === id ;
191
196
} ) ,
192
197
] ;
193
198
}
@@ -196,7 +201,7 @@ export class RegionFocusSwitcher extends Disposable {
196
201
const gristDoc = this . _getGristDoc ( ) ;
197
202
const cycleRegions = getCycleRegions ( gristDoc ) ;
198
203
this . focusRegion ( getSibling (
199
- this . current . get ( ) ,
204
+ this . _state . get ( ) . region ,
200
205
cycleRegions ,
201
206
direction ,
202
207
gristDoc
@@ -212,7 +217,7 @@ export class RegionFocusSwitcher extends Disposable {
212
217
* - make sure the internal current region info is set when user clicks on the view layout.
213
218
*/
214
219
private _onClick ( event : MouseEvent ) {
215
- const current = this . current . get ( ) ;
220
+ const current = this . _state . get ( ) . region ;
216
221
const gristDoc = this . _getGristDoc ( ) ;
217
222
if ( ! gristDoc ) {
218
223
return ;
@@ -255,12 +260,12 @@ export class RegionFocusSwitcher extends Disposable {
255
260
}
256
261
257
262
private _onEscapeKeypress ( ) {
258
- const current = this . current . get ( ) ;
263
+ const { region : current , initiator } = this . _state . get ( ) ;
259
264
// Do nothing if we are not focused on a panel
260
265
if ( current ?. type !== 'panel' ) {
261
266
return ;
262
267
}
263
- const comesFromKeyboard = this . _currentUpdateInitiator ?. type === 'cycle' ;
268
+ const comesFromKeyboard = initiator ?. type === 'cycle' ;
264
269
const panelElement = getPanelElement ( current . id ) ;
265
270
const activeElement = document . activeElement ;
266
271
const activeElementIsInPanel = panelElement ?. contains ( activeElement ) && activeElement !== panelElement ;
@@ -304,40 +309,47 @@ export class RegionFocusSwitcher extends Disposable {
304
309
this . _prevFocusedElements [ prev . id ] = document . activeElement ;
305
310
}
306
311
307
- private _onCurrentUpdate ( current : Region | undefined , prev : Region | undefined ) {
312
+ private _onStateChange ( current : State | undefined , prev : State | undefined ) {
308
313
if ( isEqual ( current , prev ) ) {
309
314
return ;
310
315
}
311
316
317
+ console . log ( 'mhl current update' , current ) ;
318
+
319
+
312
320
const gristDoc = this . _getGristDoc ( ) ;
313
- const mouseEvent = this . _currentUpdateInitiator ?. type === 'mouse'
314
- ? this . _currentUpdateInitiator . event
321
+ const mouseEvent = current ?. initiator ?. type === 'mouse'
322
+ ? current . initiator . event
315
323
: undefined ;
316
324
317
325
removeFocusRings ( ) ;
318
326
removeTabIndexes ( ) ;
319
327
if ( ! mouseEvent ) {
320
- this . _savePrevElementState ( prev ) ;
321
- if ( prev ?. type === 'panel' ) {
322
- blurPanelChild ( prev ) ;
328
+ this . _savePrevElementState ( prev ?. region ) ;
329
+ if ( prev ?. region ?. type === 'panel' ) {
330
+ blurPanelChild ( prev . region ) ;
323
331
}
324
332
}
325
333
326
- const isPanel = current ?. type === 'panel' ;
327
- const panelElement = isPanel && getPanelElement ( current . id ) ;
334
+ const isPanel = current ?. region ?. type === 'panel' ;
335
+ const panelElement = isPanel && current . region ?. id && getPanelElement ( current . region . id ) ;
328
336
329
337
// actually focus panel element if using keyboard
330
- if ( ! mouseEvent && isPanel && panelElement ) {
331
- focusPanel ( current , this . _prevFocusedElements [ current . id ] as HTMLElement | null , gristDoc ) ;
338
+ if ( ! mouseEvent && isPanel && panelElement && current . region ) {
339
+ focusPanel (
340
+ current . region as PanelRegion ,
341
+ this . _prevFocusedElements [ current . region . id as Panel ] as HTMLElement | null ,
342
+ gristDoc
343
+ ) ;
332
344
}
333
345
334
346
// just make sure view layout commands are disabled if we click on a panel
335
347
if ( mouseEvent && isPanel && panelElement && gristDoc ) {
336
348
escapeViewLayout ( gristDoc , ! ! ( mouseEvent . target as Element ) ?. closest ( `[${ ATTRS . regionId } ="right"]` ) ) ;
337
349
}
338
350
339
- if ( current ?. type === 'section' && gristDoc ) {
340
- focusSection ( current , gristDoc ) ;
351
+ if ( current ?. region ?. type === 'section' && gristDoc ) {
352
+ focusSection ( current . region , gristDoc ) ;
341
353
}
342
354
343
355
if ( current === undefined && gristDoc ) {
@@ -356,7 +368,7 @@ export class RegionFocusSwitcher extends Disposable {
356
368
}
357
369
358
370
private _toggleCreatorPanel ( ) {
359
- const current = this . current . get ( ) ;
371
+ const current = this . _state . get ( ) . region ;
360
372
const gristDoc = this . _getGristDoc ( ) ;
361
373
if ( current ?. type === 'panel' && current . id === 'right' ) {
362
374
return this . focusRegion ( gristDoc
0 commit comments