7
7
*/
8
8
9
9
import { computed , Signal , signal , WritableSignal } from '@angular/core' ;
10
- import { GridFocus , GridFocusInputs , GridFocusCell } from './grid-focus' ;
10
+ import { GridFocus , GridFocusInputs , GridFocusCell , RowCol } from './grid-focus' ;
11
11
12
12
// Helper type for test cells, extending GridFocusCell
13
13
interface TestGridCell extends GridFocusCell {
@@ -23,13 +23,13 @@ type TestSetupInputs = Partial<GridFocusInputs<TestGridCell>> & {
23
23
gridFocus ?: WritableSignal < GridFocus < TestGridCell > | undefined > ;
24
24
} ;
25
25
26
- function createTestCell (
26
+ export function createTestCell (
27
27
gridFocus : Signal < GridFocus < TestGridCell > | undefined > ,
28
28
opts : { id : string ; rowspan ?: number ; colspan ?: number } ,
29
29
) : TestGridCell {
30
30
const el = document . createElement ( 'div' ) ;
31
31
spyOn ( el , 'focus' ) . and . callThrough ( ) ;
32
- let coordinates : Signal < { row : number ; column : number } > = signal ( { row : - 1 , column : - 1 } ) ;
32
+ let coordinates : Signal < RowCol > = signal ( { row : - 1 , col : - 1 } ) ;
33
33
const cell : TestGridCell = {
34
34
id : signal ( opts . id ) ,
35
35
element : signal ( el as HTMLElement ) ,
@@ -39,13 +39,13 @@ function createTestCell(
39
39
rowindex : signal ( - 1 ) ,
40
40
colindex : signal ( - 1 ) ,
41
41
} ;
42
- coordinates = computed ( ( ) => gridFocus ( ) ?. getCoordinates ( cell ) ?? { row : - 1 , column : - 1 } ) ;
42
+ coordinates = computed ( ( ) => gridFocus ( ) ?. getCoordinates ( cell ) ?? { row : - 1 , col : - 1 } ) ;
43
43
cell . rowindex = computed ( ( ) => coordinates ( ) . row ) ;
44
- cell . colindex = computed ( ( ) => coordinates ( ) . column ) ;
44
+ cell . colindex = computed ( ( ) => coordinates ( ) . col ) ;
45
45
return cell ;
46
46
}
47
47
48
- function createTestCells (
48
+ export function createTestCells (
49
49
gridFocus : Signal < GridFocus < TestGridCell > | undefined > ,
50
50
numRows : number ,
51
51
numCols : number ,
@@ -60,7 +60,7 @@ function createTestCells(
60
60
}
61
61
62
62
// Main helper function to instantiate GridFocus and its dependencies for testing
63
- function setupGridFocus ( inputs : TestSetupInputs = { } ) : {
63
+ export function setupGridFocus ( inputs : TestSetupInputs = { } ) : {
64
64
cells : TestGridCell [ ] [ ] ;
65
65
gridFocus : GridFocus < TestGridCell > ;
66
66
} {
@@ -70,7 +70,7 @@ function setupGridFocus(inputs: TestSetupInputs = {}): {
70
70
const gridFocus = inputs . gridFocus ?? signal < GridFocus < TestGridCell > | undefined > ( undefined ) ;
71
71
const cells = inputs . cells ?? createTestCells ( gridFocus , numRows , numCols ) ;
72
72
73
- const activeCoords = inputs . activeCoords ?? signal ( { row : 0 , column : 0 } ) ;
73
+ const activeCoords = inputs . activeCoords ?? signal ( { row : 0 , col : 0 } ) ;
74
74
const focusMode = signal < 'roving' | 'activedescendant' > (
75
75
inputs . focusMode ? inputs . focusMode ( ) : 'roving' ,
76
76
) ;
@@ -95,20 +95,20 @@ function setupGridFocus(inputs: TestSetupInputs = {}): {
95
95
96
96
describe ( 'GridFocus' , ( ) => {
97
97
describe ( 'Initialization' , ( ) => {
98
- it ( 'should initialize with activeCell at {row: 0, column : 0} by default' , ( ) => {
98
+ it ( 'should initialize with activeCell at {row: 0, col : 0} by default' , ( ) => {
99
99
const { gridFocus} = setupGridFocus ( ) ;
100
- expect ( gridFocus . inputs . activeCoords ( ) ) . toEqual ( { row : 0 , column : 0 } ) ;
100
+ expect ( gridFocus . inputs . activeCoords ( ) ) . toEqual ( { row : 0 , col : 0 } ) ;
101
101
} ) ;
102
102
103
103
it ( 'should compute activeCell based on activeCell' , ( ) => {
104
104
const { gridFocus, cells} = setupGridFocus ( {
105
- activeCoords : signal ( { row : 1 , column : 1 } ) ,
105
+ activeCoords : signal ( { row : 1 , col : 1 } ) ,
106
106
} ) ;
107
107
expect ( gridFocus . activeCell ( ) ) . toBe ( cells [ 1 ] [ 1 ] ) ;
108
108
} ) ;
109
109
110
110
it ( 'should compute activeCell correctly when rowspan and colspan are set' , ( ) => {
111
- const activeCoords = signal ( { row : 0 , column : 0 } ) ;
111
+ const activeCoords = signal ( { row : 0 , col : 0 } ) ;
112
112
const gridFocusSignal = signal < GridFocus < TestGridCell > | undefined > ( undefined ) ;
113
113
114
114
// Visualization of this irregular grid.
@@ -130,24 +130,58 @@ describe('GridFocus', () => {
130
130
gridFocus : gridFocusSignal ,
131
131
} ) ;
132
132
133
- activeCoords . set ( { row : 0 , column : 0 } ) ;
133
+ activeCoords . set ( { row : 0 , col : 0 } ) ;
134
134
expect ( gridFocus . activeCell ( ) ) . toBe ( cell_0_0 ) ;
135
- activeCoords . set ( { row : 0 , column : 1 } ) ;
135
+ activeCoords . set ( { row : 0 , col : 1 } ) ;
136
136
expect ( gridFocus . activeCell ( ) ) . toBe ( cell_0_0 ) ;
137
- activeCoords . set ( { row : 1 , column : 0 } ) ;
137
+ activeCoords . set ( { row : 1 , col : 0 } ) ;
138
138
expect ( gridFocus . activeCell ( ) ) . toBe ( cell_0_0 ) ;
139
- activeCoords . set ( { row : 1 , column : 1 } ) ;
139
+ activeCoords . set ( { row : 1 , col : 1 } ) ;
140
140
expect ( gridFocus . activeCell ( ) ) . toBe ( cell_0_0 ) ;
141
141
142
- activeCoords . set ( { row : 0 , column : 2 } ) ;
142
+ activeCoords . set ( { row : 0 , col : 2 } ) ;
143
143
expect ( gridFocus . activeCell ( ) ) . toBe ( cell_0_2 ) ;
144
144
145
- activeCoords . set ( { row : 1 , column : 2 } ) ;
145
+ activeCoords . set ( { row : 1 , col : 2 } ) ;
146
146
expect ( gridFocus . activeCell ( ) ) . toBe ( cell_1_2 ) ;
147
147
} ) ;
148
+
149
+ it ( 'should compute rowCount and colCount correctly' , ( ) => {
150
+ const { gridFocus} = setupGridFocus ( {
151
+ numRows : 2 ,
152
+ numCols : 3 ,
153
+ } ) ;
154
+ expect ( gridFocus . rowCount ( ) ) . toBe ( 2 ) ;
155
+ expect ( gridFocus . colCount ( ) ) . toBe ( 3 ) ;
156
+ } ) ;
157
+
158
+ it ( 'should compute rowCount and colCount correctly when rowspan and colspan are set' , ( ) => {
159
+ const gridFocusSignal = signal < GridFocus < TestGridCell > | undefined > ( undefined ) ;
160
+
161
+ // Visualization of this irregular grid.
162
+ //
163
+ // +---+---+---+
164
+ // | |0,2|
165
+ // + 0,0 +---+
166
+ // | |1,2|
167
+ // +---+---+---+
168
+ //
169
+ const cell_0_0 = createTestCell ( gridFocusSignal , { id : `cell-0-0` , rowspan : 2 , colspan : 2 } ) ;
170
+ const cell_0_2 = createTestCell ( gridFocusSignal , { id : `cell-0-2` } ) ;
171
+ const cell_1_2 = createTestCell ( gridFocusSignal , { id : `cell-1-2` } ) ;
172
+ const cells = signal < TestGridCell [ ] [ ] > ( [ [ cell_0_0 , cell_0_2 ] , [ cell_1_2 ] ] ) ;
173
+
174
+ const { gridFocus} = setupGridFocus ( {
175
+ cells,
176
+ gridFocus : gridFocusSignal ,
177
+ } ) ;
178
+
179
+ expect ( gridFocus . rowCount ( ) ) . toBe ( 2 ) ;
180
+ expect ( gridFocus . colCount ( ) ) . toBe ( 3 ) ;
181
+ } ) ;
148
182
} ) ;
149
183
150
- describe ( 'isGridDisabled() ' , ( ) => {
184
+ describe ( 'isGridDisabled' , ( ) => {
151
185
it ( 'should return true if inputs.disabled is true' , ( ) => {
152
186
const { gridFocus} = setupGridFocus ( { disabled : signal ( true ) } ) ;
153
187
expect ( gridFocus . isGridDisabled ( ) ) . toBeTrue ( ) ;
@@ -171,7 +205,7 @@ describe('GridFocus', () => {
171
205
} ) ;
172
206
} ) ;
173
207
174
- describe ( 'getActiveDescendant() ' , ( ) => {
208
+ describe ( 'getActiveDescendant' , ( ) => {
175
209
it ( 'should return undefined if focusMode is "roving"' , ( ) => {
176
210
const { gridFocus} = setupGridFocus ( { focusMode : signal ( 'roving' ) } ) ;
177
211
expect ( gridFocus . getActiveDescendant ( ) ) . toBeUndefined ( ) ;
@@ -188,13 +222,13 @@ describe('GridFocus', () => {
188
222
it ( 'should return the activeCell id if focusMode is "activedescendant"' , ( ) => {
189
223
const { gridFocus, cells} = setupGridFocus ( {
190
224
focusMode : signal ( 'activedescendant' ) ,
191
- activeCoords : signal ( { row : 2 , column : 2 } ) ,
225
+ activeCoords : signal ( { row : 2 , col : 2 } ) ,
192
226
} ) ;
193
227
expect ( gridFocus . getActiveDescendant ( ) ) . toBe ( cells [ 2 ] [ 2 ] . id ( ) ) ;
194
228
} ) ;
195
229
} ) ;
196
230
197
- describe ( 'getGridTabindex() ' , ( ) => {
231
+ describe ( 'getGridTabindex' , ( ) => {
198
232
it ( 'should return 0 if grid is disabled' , ( ) => {
199
233
const { gridFocus} = setupGridFocus ( { disabled : signal ( true ) } ) ;
200
234
expect ( gridFocus . getGridTabindex ( ) ) . toBe ( 0 ) ;
@@ -211,7 +245,7 @@ describe('GridFocus', () => {
211
245
} ) ;
212
246
} ) ;
213
247
214
- describe ( 'getCellTabindex(cell) ' , ( ) => {
248
+ describe ( 'getCellTabindex' , ( ) => {
215
249
it ( 'should return -1 if grid is disabled' , ( ) => {
216
250
const { gridFocus, cells} = setupGridFocus ( {
217
251
numRows : 1 ,
@@ -247,7 +281,7 @@ describe('GridFocus', () => {
247
281
} ) ;
248
282
} ) ;
249
283
250
- describe ( 'isFocusable(cell) ' , ( ) => {
284
+ describe ( 'isFocusable' , ( ) => {
251
285
it ( 'should return true if cell is not disabled' , ( ) => {
252
286
const { gridFocus, cells} = setupGridFocus ( {
253
287
numRows : 1 ,
@@ -283,65 +317,127 @@ describe('GridFocus', () => {
283
317
} ) ;
284
318
} ) ;
285
319
286
- describe ( 'focus(cell)' , ( ) => {
320
+ describe ( 'focusCoordinates' , ( ) => {
321
+ it ( 'should return false and not change state if grid is disabled' , ( ) => {
322
+ const activeCoords = signal ( { row : 0 , col : 0 } ) ;
323
+ const { gridFocus, cells} = setupGridFocus ( {
324
+ activeCoords,
325
+ disabled : signal ( true ) ,
326
+ } ) ;
327
+
328
+ const success = gridFocus . focusCoordinates ( { row : 1 , col : 0 } ) ;
329
+
330
+ expect ( success ) . toBeFalse ( ) ;
331
+ expect ( activeCoords ( ) ) . toEqual ( { row : 0 , col : 0 } ) ;
332
+ expect ( cells [ 1 ] [ 0 ] . element ( ) . focus ) . not . toHaveBeenCalled ( ) ;
333
+ } ) ;
334
+
335
+ it ( 'should return false and not change state if cell is not focusable' , ( ) => {
336
+ const activeCoords = signal ( { row : 0 , col : 0 } ) ;
337
+ const { gridFocus, cells} = setupGridFocus ( { activeCoords} ) ;
338
+ cells [ 1 ] [ 0 ] . disabled . set ( true ) ;
339
+
340
+ const success = gridFocus . focusCoordinates ( { row : 1 , col : 0 } ) ;
341
+
342
+ expect ( success ) . toBeFalse ( ) ;
343
+ expect ( activeCoords ( ) ) . toEqual ( { row : 0 , col : 0 } ) ;
344
+ expect ( cells [ 1 ] [ 0 ] . element ( ) . focus ) . not . toHaveBeenCalled ( ) ;
345
+ } ) ;
346
+
347
+ it ( 'should focus cell, update activeCell and prevActiveCell in "roving" mode' , ( ) => {
348
+ const activeCoords = signal ( { row : 0 , col : 0 } ) ;
349
+ const { gridFocus, cells} = setupGridFocus ( {
350
+ activeCoords,
351
+ focusMode : signal ( 'roving' ) ,
352
+ } ) ;
353
+
354
+ const success = gridFocus . focusCoordinates ( { row : 1 , col : 0 } ) ;
355
+
356
+ expect ( success ) . toBeTrue ( ) ;
357
+ expect ( activeCoords ( ) ) . toEqual ( { row : 1 , col : 0 } ) ;
358
+ expect ( cells [ 1 ] [ 0 ] . element ( ) . focus ) . toHaveBeenCalled ( ) ;
359
+
360
+ expect ( gridFocus . activeCell ( ) ) . toBe ( cells [ 1 ] [ 0 ] ) ;
361
+ expect ( gridFocus . prevActiveCoords ( ) ) . toEqual ( { row : 0 , col : 0 } ) ;
362
+ } ) ;
363
+
364
+ it ( 'should update activeCell and prevActiveCell but not call element.focus in "activedescendant" mode' , ( ) => {
365
+ const activeCoords = signal ( { row : 0 , col : 0 } ) ;
366
+ const { gridFocus, cells} = setupGridFocus ( {
367
+ activeCoords,
368
+ focusMode : signal ( 'activedescendant' ) ,
369
+ } ) ;
370
+
371
+ const success = gridFocus . focusCoordinates ( { row : 1 , col : 0 } ) ;
372
+
373
+ expect ( success ) . toBeTrue ( ) ;
374
+ expect ( activeCoords ( ) ) . toEqual ( { row : 1 , col : 0 } ) ;
375
+ expect ( cells [ 1 ] [ 0 ] . element ( ) . focus ) . not . toHaveBeenCalled ( ) ;
376
+
377
+ expect ( gridFocus . activeCell ( ) ) . toBe ( cells [ 1 ] [ 0 ] ) ;
378
+ expect ( gridFocus . prevActiveCoords ( ) ) . toEqual ( { row : 0 , col : 0 } ) ;
379
+ } ) ;
380
+ } ) ;
381
+
382
+ describe ( 'focusCell' , ( ) => {
287
383
it ( 'should return false and not change state if grid is disabled' , ( ) => {
288
- const activeCoords = signal ( { row : 0 , column : 0 } ) ;
384
+ const activeCoords = signal ( { row : 0 , col : 0 } ) ;
289
385
const { gridFocus, cells} = setupGridFocus ( {
290
386
activeCoords,
291
387
disabled : signal ( true ) ,
292
388
} ) ;
293
389
294
- const success = gridFocus . focus ( { row : 1 , column : 0 } ) ;
390
+ const success = gridFocus . focusCell ( cells [ 1 ] [ 0 ] ) ;
295
391
296
392
expect ( success ) . toBeFalse ( ) ;
297
- expect ( activeCoords ( ) ) . toEqual ( { row : 0 , column : 0 } ) ;
393
+ expect ( activeCoords ( ) ) . toEqual ( { row : 0 , col : 0 } ) ;
298
394
expect ( cells [ 1 ] [ 0 ] . element ( ) . focus ) . not . toHaveBeenCalled ( ) ;
299
395
} ) ;
300
396
301
397
it ( 'should return false and not change state if cell is not focusable' , ( ) => {
302
- const activeCoords = signal ( { row : 0 , column : 0 } ) ;
398
+ const activeCoords = signal ( { row : 0 , col : 0 } ) ;
303
399
const { gridFocus, cells} = setupGridFocus ( { activeCoords} ) ;
304
400
cells [ 1 ] [ 0 ] . disabled . set ( true ) ;
305
401
306
- const success = gridFocus . focus ( { row : 1 , column : 0 } ) ;
402
+ const success = gridFocus . focusCell ( cells [ 1 ] [ 0 ] ) ;
307
403
308
404
expect ( success ) . toBeFalse ( ) ;
309
- expect ( activeCoords ( ) ) . toEqual ( { row : 0 , column : 0 } ) ;
405
+ expect ( activeCoords ( ) ) . toEqual ( { row : 0 , col : 0 } ) ;
310
406
expect ( cells [ 1 ] [ 0 ] . element ( ) . focus ) . not . toHaveBeenCalled ( ) ;
311
407
} ) ;
312
408
313
409
it ( 'should focus cell, update activeCell and prevActiveCell in "roving" mode' , ( ) => {
314
- const activeCoords = signal ( { row : 0 , column : 0 } ) ;
410
+ const activeCoords = signal ( { row : 0 , col : 0 } ) ;
315
411
const { gridFocus, cells} = setupGridFocus ( {
316
412
activeCoords,
317
413
focusMode : signal ( 'roving' ) ,
318
414
} ) ;
319
415
320
- const success = gridFocus . focus ( { row : 1 , column : 0 } ) ;
416
+ const success = gridFocus . focusCell ( cells [ 1 ] [ 0 ] ) ;
321
417
322
418
expect ( success ) . toBeTrue ( ) ;
323
- expect ( activeCoords ( ) ) . toEqual ( { row : 1 , column : 0 } ) ;
419
+ expect ( activeCoords ( ) ) . toEqual ( { row : 1 , col : 0 } ) ;
324
420
expect ( cells [ 1 ] [ 0 ] . element ( ) . focus ) . toHaveBeenCalled ( ) ;
325
421
326
422
expect ( gridFocus . activeCell ( ) ) . toBe ( cells [ 1 ] [ 0 ] ) ;
327
- expect ( gridFocus . prevActiveCoords ( ) ) . toEqual ( { row : 0 , column : 0 } ) ;
423
+ expect ( gridFocus . prevActiveCoords ( ) ) . toEqual ( { row : 0 , col : 0 } ) ;
328
424
} ) ;
329
425
330
426
it ( 'should update activeCell and prevActiveCell but not call element.focus in "activedescendant" mode' , ( ) => {
331
- const activeCoords = signal ( { row : 0 , column : 0 } ) ;
427
+ const activeCoords = signal ( { row : 0 , col : 0 } ) ;
332
428
const { gridFocus, cells} = setupGridFocus ( {
333
429
activeCoords,
334
430
focusMode : signal ( 'activedescendant' ) ,
335
431
} ) ;
336
432
337
- const success = gridFocus . focus ( { row : 1 , column : 0 } ) ;
433
+ const success = gridFocus . focusCell ( cells [ 1 ] [ 0 ] ) ;
338
434
339
435
expect ( success ) . toBeTrue ( ) ;
340
- expect ( activeCoords ( ) ) . toEqual ( { row : 1 , column : 0 } ) ;
436
+ expect ( activeCoords ( ) ) . toEqual ( { row : 1 , col : 0 } ) ;
341
437
expect ( cells [ 1 ] [ 0 ] . element ( ) . focus ) . not . toHaveBeenCalled ( ) ;
342
438
343
439
expect ( gridFocus . activeCell ( ) ) . toBe ( cells [ 1 ] [ 0 ] ) ;
344
- expect ( gridFocus . prevActiveCoords ( ) ) . toEqual ( { row : 0 , column : 0 } ) ;
440
+ expect ( gridFocus . prevActiveCoords ( ) ) . toEqual ( { row : 0 , col : 0 } ) ;
345
441
} ) ;
346
442
} ) ;
347
443
} ) ;
0 commit comments