@react-aria/grid 3.10.5 → 3.11.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (107) hide show
  1. package/dist/GridKeyboardDelegate.main.js +104 -43
  2. package/dist/GridKeyboardDelegate.main.js.map +1 -1
  3. package/dist/GridKeyboardDelegate.mjs +104 -43
  4. package/dist/GridKeyboardDelegate.module.js +104 -43
  5. package/dist/GridKeyboardDelegate.module.js.map +1 -1
  6. package/dist/ar-AE.main.js.map +1 -1
  7. package/dist/ar-AE.module.js.map +1 -1
  8. package/dist/bg-BG.main.js.map +1 -1
  9. package/dist/bg-BG.module.js.map +1 -1
  10. package/dist/cs-CZ.main.js.map +1 -1
  11. package/dist/cs-CZ.module.js.map +1 -1
  12. package/dist/da-DK.main.js.map +1 -1
  13. package/dist/da-DK.module.js.map +1 -1
  14. package/dist/de-DE.main.js.map +1 -1
  15. package/dist/de-DE.module.js.map +1 -1
  16. package/dist/el-GR.main.js.map +1 -1
  17. package/dist/el-GR.module.js.map +1 -1
  18. package/dist/en-US.main.js.map +1 -1
  19. package/dist/en-US.module.js.map +1 -1
  20. package/dist/es-ES.main.js.map +1 -1
  21. package/dist/es-ES.module.js.map +1 -1
  22. package/dist/et-EE.main.js.map +1 -1
  23. package/dist/et-EE.module.js.map +1 -1
  24. package/dist/fi-FI.main.js.map +1 -1
  25. package/dist/fi-FI.module.js.map +1 -1
  26. package/dist/fr-FR.main.js.map +1 -1
  27. package/dist/fr-FR.module.js.map +1 -1
  28. package/dist/he-IL.main.js.map +1 -1
  29. package/dist/he-IL.module.js.map +1 -1
  30. package/dist/hr-HR.main.js.map +1 -1
  31. package/dist/hr-HR.module.js.map +1 -1
  32. package/dist/hu-HU.main.js.map +1 -1
  33. package/dist/hu-HU.module.js.map +1 -1
  34. package/dist/it-IT.main.js.map +1 -1
  35. package/dist/it-IT.module.js.map +1 -1
  36. package/dist/ja-JP.main.js.map +1 -1
  37. package/dist/ja-JP.module.js.map +1 -1
  38. package/dist/ko-KR.main.js.map +1 -1
  39. package/dist/ko-KR.module.js.map +1 -1
  40. package/dist/lt-LT.main.js.map +1 -1
  41. package/dist/lt-LT.module.js.map +1 -1
  42. package/dist/lv-LV.main.js.map +1 -1
  43. package/dist/lv-LV.module.js.map +1 -1
  44. package/dist/nb-NO.main.js.map +1 -1
  45. package/dist/nb-NO.module.js.map +1 -1
  46. package/dist/nl-NL.main.js.map +1 -1
  47. package/dist/nl-NL.module.js.map +1 -1
  48. package/dist/pl-PL.main.js.map +1 -1
  49. package/dist/pl-PL.module.js.map +1 -1
  50. package/dist/pt-BR.main.js.map +1 -1
  51. package/dist/pt-BR.module.js.map +1 -1
  52. package/dist/pt-PT.main.js.map +1 -1
  53. package/dist/pt-PT.module.js.map +1 -1
  54. package/dist/ro-RO.main.js.map +1 -1
  55. package/dist/ro-RO.module.js.map +1 -1
  56. package/dist/ru-RU.main.js.map +1 -1
  57. package/dist/ru-RU.module.js.map +1 -1
  58. package/dist/sk-SK.main.js.map +1 -1
  59. package/dist/sk-SK.module.js.map +1 -1
  60. package/dist/sl-SI.main.js.map +1 -1
  61. package/dist/sl-SI.module.js.map +1 -1
  62. package/dist/sr-SP.main.js.map +1 -1
  63. package/dist/sr-SP.module.js.map +1 -1
  64. package/dist/sv-SE.main.js.map +1 -1
  65. package/dist/sv-SE.module.js.map +1 -1
  66. package/dist/tr-TR.main.js.map +1 -1
  67. package/dist/tr-TR.module.js.map +1 -1
  68. package/dist/types.d.ts +12 -12
  69. package/dist/types.d.ts.map +1 -1
  70. package/dist/uk-UA.main.js.map +1 -1
  71. package/dist/uk-UA.module.js.map +1 -1
  72. package/dist/useGrid.main.js +1 -1
  73. package/dist/useGrid.main.js.map +1 -1
  74. package/dist/useGrid.mjs +1 -1
  75. package/dist/useGrid.module.js +1 -1
  76. package/dist/useGrid.module.js.map +1 -1
  77. package/dist/useGridCell.main.js +27 -20
  78. package/dist/useGridCell.main.js.map +1 -1
  79. package/dist/useGridCell.mjs +27 -20
  80. package/dist/useGridCell.module.js +27 -20
  81. package/dist/useGridCell.module.js.map +1 -1
  82. package/dist/useGridRow.main.js +4 -1
  83. package/dist/useGridRow.main.js.map +1 -1
  84. package/dist/useGridRow.mjs +4 -1
  85. package/dist/useGridRow.module.js +4 -1
  86. package/dist/useGridRow.module.js.map +1 -1
  87. package/dist/useGridSelectionAnnouncement.main.js.map +1 -1
  88. package/dist/useGridSelectionAnnouncement.module.js.map +1 -1
  89. package/dist/useHighlightSelectionDescription.main.js +1 -1
  90. package/dist/useHighlightSelectionDescription.main.js.map +1 -1
  91. package/dist/useHighlightSelectionDescription.mjs +1 -1
  92. package/dist/useHighlightSelectionDescription.module.js +1 -1
  93. package/dist/useHighlightSelectionDescription.module.js.map +1 -1
  94. package/dist/utils.main.js.map +1 -1
  95. package/dist/utils.module.js.map +1 -1
  96. package/dist/zh-CN.main.js.map +1 -1
  97. package/dist/zh-CN.module.js.map +1 -1
  98. package/dist/zh-TW.main.js.map +1 -1
  99. package/dist/zh-TW.module.js.map +1 -1
  100. package/package.json +16 -16
  101. package/src/GridKeyboardDelegate.ts +120 -53
  102. package/src/useGrid.ts +1 -1
  103. package/src/useGridCell.ts +37 -33
  104. package/src/useGridRow.ts +2 -2
  105. package/src/useGridSelectionAnnouncement.ts +1 -1
  106. package/src/useHighlightSelectionDescription.ts +1 -1
  107. package/src/utils.ts +2 -2
@@ -1 +1 @@
1
- {"mappings":";AAAA,4BAAiB;IAAG,kBAAkB,CAAC,OAAS,CAAC,gCAAI,EAAE,KAAK,IAAI,CAAC,gBAAE,CAAC;IAClE,qBAAqB,CAAC,gFAAU,CAAC;IACjC,UAAU,CAAC,gBAAE,CAAC;IACd,eAAe,CAAC,gEAAQ,CAAC;IACzB,iBAAiB,CAAC,MAAM,YAAc,CAAC,EAAE,UAAU,MAAM,CAAC,KAAK,KAAK,EAAE;YAAC,MAAM,CAAC,wDAAO,CAAC;YAAE,KAAK,IAAM,CAAC,yBAAI,EAAE,UAAU,MAAM,CAAC,KAAK,KAAK,EAAE,yBAAI,CAAC;YAAE,OAAO,IAAM,CAAC,yBAAI,EAAE,UAAU,MAAM,CAAC,KAAK,KAAK,EAAE,yBAAI,CAAC;QAAA,GAAG,QAAC,CAAC;IACzM,gBAAgB,CAAC,OAAS,CAAC,gCAAI,EAAE,KAAK,IAAI,CAAC,gBAAE,CAAC;AAChD","sources":["packages/@react-aria/grid/intl/zh-TW.json"],"sourcesContent":["{\n \"deselectedItem\": \"未選取「{item}」。\",\n \"longPressToSelect\": \"長按以進入選擇模式。\",\n \"select\": \"選取\",\n \"selectedAll\": \"已選取所有項目。\",\n \"selectedCount\": \"{count, plural, =0 {未選取任何項目} one {已選取 # 個項目} other {已選取 # 個項目}}。\",\n \"selectedItem\": \"已選取「{item}」。\"\n}\n"],"names":[],"version":3,"file":"zh-TW.module.js.map"}
1
+ {"mappings":";AAAA,4BAAiB;IAAG,kBAAkB,CAAC,OAAS,CAAC,gCAAI,EAAE,KAAK,IAAI,CAAC,gBAAE,CAAC;IAClE,qBAAqB,CAAC,gFAAU,CAAC;IACjC,UAAU,CAAC,gBAAE,CAAC;IACd,eAAe,CAAC,gEAAQ,CAAC;IACzB,iBAAiB,CAAC,MAAM,YAAc,GAAG,UAAU,MAAM,CAAC,KAAK,KAAK,EAAE;YAAC,MAAM,CAAC,wDAAO,CAAC;YAAE,KAAK,IAAM,CAAC,yBAAI,EAAE,UAAU,MAAM,CAAC,KAAK,KAAK,EAAE,yBAAI,CAAC;YAAE,OAAO,IAAM,CAAC,yBAAI,EAAE,UAAU,MAAM,CAAC,KAAK,KAAK,EAAE,yBAAI,CAAC;QAAA,GAAG,QAAC,CAAC;IACzM,gBAAgB,CAAC,OAAS,CAAC,gCAAI,EAAE,KAAK,IAAI,CAAC,gBAAE,CAAC;AAChD","sources":["packages/@react-aria/grid/intl/zh-TW.json"],"sourcesContent":["{\n \"deselectedItem\": \"未選取「{item}」。\",\n \"longPressToSelect\": \"長按以進入選擇模式。\",\n \"select\": \"選取\",\n \"selectedAll\": \"已選取所有項目。\",\n \"selectedCount\": \"{count, plural, =0 {未選取任何項目} one {已選取 # 個項目} other {已選取 # 個項目}}。\",\n \"selectedItem\": \"已選取「{item}」。\"\n}\n"],"names":[],"version":3,"file":"zh-TW.module.js.map"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@react-aria/grid",
3
- "version": "3.10.5",
3
+ "version": "3.11.1",
4
4
  "description": "Spectrum UI components in React",
5
5
  "license": "Apache-2.0",
6
6
  "main": "dist/main.js",
@@ -22,26 +22,26 @@
22
22
  "url": "https://github.com/adobe/react-spectrum"
23
23
  },
24
24
  "dependencies": {
25
- "@react-aria/focus": "^3.18.4",
26
- "@react-aria/i18n": "^3.12.3",
27
- "@react-aria/interactions": "^3.22.4",
28
- "@react-aria/live-announcer": "^3.4.0",
29
- "@react-aria/selection": "^3.20.1",
30
- "@react-aria/utils": "^3.25.3",
31
- "@react-stately/collections": "^3.11.0",
32
- "@react-stately/grid": "^3.9.3",
33
- "@react-stately/selection": "^3.17.0",
34
- "@react-types/checkbox": "^3.8.4",
35
- "@react-types/grid": "^3.2.9",
36
- "@react-types/shared": "^3.25.0",
25
+ "@react-aria/focus": "^3.19.1",
26
+ "@react-aria/i18n": "^3.12.5",
27
+ "@react-aria/interactions": "^3.23.0",
28
+ "@react-aria/live-announcer": "^3.4.1",
29
+ "@react-aria/selection": "^3.22.0",
30
+ "@react-aria/utils": "^3.27.0",
31
+ "@react-stately/collections": "^3.12.1",
32
+ "@react-stately/grid": "^3.10.1",
33
+ "@react-stately/selection": "^3.19.0",
34
+ "@react-types/checkbox": "^3.9.1",
35
+ "@react-types/grid": "^3.2.11",
36
+ "@react-types/shared": "^3.27.0",
37
37
  "@swc/helpers": "^0.5.0"
38
38
  },
39
39
  "peerDependencies": {
40
- "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0",
41
- "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0"
40
+ "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1",
41
+ "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1"
42
42
  },
43
43
  "publishConfig": {
44
44
  "access": "public"
45
45
  },
46
- "gitHead": "8e0a28d188cdbdbd2b32296fa034b1b02ddde229"
46
+ "gitHead": "09e7f44bebdc9d89122926b2b439a0a38a2814ea"
47
47
  }
@@ -33,7 +33,7 @@ export class GridKeyboardDelegate<T, C extends GridCollection<T>> implements Key
33
33
  protected disabledKeys: Set<Key>;
34
34
  protected disabledBehavior: DisabledBehavior;
35
35
  protected direction: Direction;
36
- protected collator: Intl.Collator;
36
+ protected collator: Intl.Collator | undefined;
37
37
  protected layoutDelegate: LayoutDelegate;
38
38
  protected focusMode;
39
39
 
@@ -43,7 +43,10 @@ export class GridKeyboardDelegate<T, C extends GridCollection<T>> implements Key
43
43
  this.disabledBehavior = options.disabledBehavior || 'all';
44
44
  this.direction = options.direction;
45
45
  this.collator = options.collator;
46
- this.layoutDelegate = options.layoutDelegate || (options.layout ? new DeprecatedLayoutDelegate(options.layout) : new DOMLayoutDelegate(options.ref));
46
+ if (!options.layout && !options.ref) {
47
+ throw new Error('Either a layout or a ref must be specified.');
48
+ }
49
+ this.layoutDelegate = options.layoutDelegate || (options.layout ? new DeprecatedLayoutDelegate(options.layout) : new DOMLayoutDelegate(options.ref!));
47
50
  this.focusMode = options.focusMode || 'row';
48
51
  }
49
52
 
@@ -66,12 +69,16 @@ export class GridKeyboardDelegate<T, C extends GridCollection<T>> implements Key
66
69
 
67
70
  while (key != null) {
68
71
  let item = this.collection.getItem(key);
72
+ if (!item) {
73
+ return null;
74
+ }
69
75
  if (!this.isDisabled(item) && (!pred || pred(item))) {
70
76
  return key;
71
77
  }
72
78
 
73
79
  key = this.collection.getKeyBefore(key);
74
80
  }
81
+ return null;
75
82
  }
76
83
 
77
84
  protected findNextKey(fromKey?: Key, pred?: (item: Node<T>) => boolean) {
@@ -81,23 +88,34 @@ export class GridKeyboardDelegate<T, C extends GridCollection<T>> implements Key
81
88
 
82
89
  while (key != null) {
83
90
  let item = this.collection.getItem(key);
91
+ if (!item) {
92
+ return null;
93
+ }
84
94
  if (!this.isDisabled(item) && (!pred || pred(item))) {
85
95
  return key;
86
96
  }
87
97
 
88
98
  key = this.collection.getKeyAfter(key);
99
+ if (key == null) {
100
+ return null;
101
+ }
89
102
  }
103
+ return null;
90
104
  }
91
105
 
92
- getKeyBelow(key: Key) {
106
+ getKeyBelow(fromKey: Key) {
107
+ let key: Key | null = fromKey;
93
108
  let startItem = this.collection.getItem(key);
94
109
  if (!startItem) {
95
- return;
110
+ return null;
96
111
  }
97
112
 
98
113
  // If focus was on a cell, start searching from the parent row
99
114
  if (this.isCell(startItem)) {
100
- key = startItem.parentKey;
115
+ key = startItem.parentKey ?? null;
116
+ }
117
+ if (key == null) {
118
+ return null;
101
119
  }
102
120
 
103
121
  // Find the next item
@@ -106,7 +124,10 @@ export class GridKeyboardDelegate<T, C extends GridCollection<T>> implements Key
106
124
  // If focus was on a cell, focus the cell with the same index in the next row.
107
125
  if (this.isCell(startItem)) {
108
126
  let item = this.collection.getItem(key);
109
- return getNthItem(getChildNodes(item, this.collection), startItem.index).key;
127
+ if (!item) {
128
+ return null;
129
+ }
130
+ return getNthItem(getChildNodes(item, this.collection), startItem.index ?? 0)?.key ?? null;
110
131
  }
111
132
 
112
133
  // Otherwise, focus the next row
@@ -114,17 +135,22 @@ export class GridKeyboardDelegate<T, C extends GridCollection<T>> implements Key
114
135
  return key;
115
136
  }
116
137
  }
138
+ return null;
117
139
  }
118
140
 
119
- getKeyAbove(key: Key) {
141
+ getKeyAbove(fromKey: Key) {
142
+ let key: Key | null = fromKey;
120
143
  let startItem = this.collection.getItem(key);
121
144
  if (!startItem) {
122
- return;
145
+ return null;
123
146
  }
124
147
 
125
148
  // If focus is on a cell, start searching from the parent row
126
149
  if (this.isCell(startItem)) {
127
- key = startItem.parentKey;
150
+ key = startItem.parentKey ?? null;
151
+ }
152
+ if (key == null) {
153
+ return null;
128
154
  }
129
155
 
130
156
  // Find the previous item
@@ -133,7 +159,10 @@ export class GridKeyboardDelegate<T, C extends GridCollection<T>> implements Key
133
159
  // If focus was on a cell, focus the cell with the same index in the previous row.
134
160
  if (this.isCell(startItem)) {
135
161
  let item = this.collection.getItem(key);
136
- return getNthItem(getChildNodes(item, this.collection), startItem.index).key;
162
+ if (!item) {
163
+ return null;
164
+ }
165
+ return getNthItem(getChildNodes(item, this.collection), startItem.index ?? 0)?.key || null;
137
166
  }
138
167
 
139
168
  // Otherwise, focus the previous row
@@ -141,141 +170,165 @@ export class GridKeyboardDelegate<T, C extends GridCollection<T>> implements Key
141
170
  return key;
142
171
  }
143
172
  }
173
+ return null;
144
174
  }
145
175
 
146
176
  getKeyRightOf(key: Key) {
147
177
  let item = this.collection.getItem(key);
148
178
  if (!item) {
149
- return;
179
+ return null;
150
180
  }
151
181
 
152
182
  // If focus is on a row, focus the first child cell.
153
183
  if (this.isRow(item)) {
154
184
  let children = getChildNodes(item, this.collection);
155
- return this.direction === 'rtl'
156
- ? getLastItem(children).key
157
- : getFirstItem(children).key;
185
+ return (this.direction === 'rtl'
186
+ ? getLastItem(children)?.key
187
+ : getFirstItem(children)?.key) ?? null;
158
188
  }
159
189
 
160
190
  // If focus is on a cell, focus the next cell if any,
161
191
  // otherwise focus the parent row.
162
- if (this.isCell(item)) {
192
+ if (this.isCell(item) && item.parentKey != null) {
163
193
  let parent = this.collection.getItem(item.parentKey);
194
+ if (!parent) {
195
+ return null;
196
+ }
164
197
  let children = getChildNodes(parent, this.collection);
165
- let next = this.direction === 'rtl'
198
+ let next = (this.direction === 'rtl'
166
199
  ? getNthItem(children, item.index - 1)
167
- : getNthItem(children, item.index + 1);
200
+ : getNthItem(children, item.index + 1)) ?? null;
168
201
 
169
202
  if (next) {
170
- return next.key;
203
+ return next.key ?? null;
171
204
  }
172
205
 
173
206
  // focus row only if focusMode is set to row
174
207
  if (this.focusMode === 'row') {
175
- return item.parentKey;
208
+ return item.parentKey ?? null;
176
209
  }
177
210
 
178
- return this.direction === 'rtl' ? this.getFirstKey(key) : this.getLastKey(key);
211
+ return (this.direction === 'rtl' ? this.getFirstKey(key) : this.getLastKey(key)) ?? null;
179
212
  }
213
+ return null;
180
214
  }
181
215
 
182
216
  getKeyLeftOf(key: Key) {
183
217
  let item = this.collection.getItem(key);
184
218
  if (!item) {
185
- return;
219
+ return null;
186
220
  }
187
221
 
188
222
  // If focus is on a row, focus the last child cell.
189
223
  if (this.isRow(item)) {
190
224
  let children = getChildNodes(item, this.collection);
191
- return this.direction === 'rtl'
192
- ? getFirstItem(children).key
193
- : getLastItem(children).key;
225
+ return (this.direction === 'rtl'
226
+ ? getFirstItem(children)?.key
227
+ : getLastItem(children)?.key) ?? null;
194
228
  }
195
229
 
196
230
  // If focus is on a cell, focus the previous cell if any,
197
231
  // otherwise focus the parent row.
198
- if (this.isCell(item)) {
232
+ if (this.isCell(item) && item.parentKey != null) {
199
233
  let parent = this.collection.getItem(item.parentKey);
234
+ if (!parent) {
235
+ return null;
236
+ }
200
237
  let children = getChildNodes(parent, this.collection);
201
- let prev = this.direction === 'rtl'
238
+ let prev = (this.direction === 'rtl'
202
239
  ? getNthItem(children, item.index + 1)
203
- : getNthItem(children, item.index - 1);
240
+ : getNthItem(children, item.index - 1)) ?? null;
204
241
 
205
242
  if (prev) {
206
- return prev.key;
243
+ return prev.key ?? null;
207
244
  }
208
245
 
209
246
  // focus row only if focusMode is set to row
210
247
  if (this.focusMode === 'row') {
211
- return item.parentKey;
248
+ return item.parentKey ?? null;
212
249
  }
213
250
 
214
- return this.direction === 'rtl' ? this.getLastKey(key) : this.getFirstKey(key);
251
+ return (this.direction === 'rtl' ? this.getLastKey(key) : this.getFirstKey(key)) ?? null;
215
252
  }
253
+ return null;
216
254
  }
217
255
 
218
- getFirstKey(key?: Key, global?: boolean) {
219
- let item: Node<T>;
256
+ getFirstKey(fromKey?: Key, global?: boolean) {
257
+ let key: Key | null = fromKey ?? null;
258
+ let item: Node<T> | undefined | null;
220
259
  if (key != null) {
221
260
  item = this.collection.getItem(key);
222
261
  if (!item) {
223
- return;
262
+ return null;
224
263
  }
225
264
 
226
265
  // If global flag is not set, and a cell is currently focused,
227
266
  // move focus to the first cell in the parent row.
228
- if (this.isCell(item) && !global) {
267
+ if (this.isCell(item) && !global && item.parentKey != null) {
229
268
  let parent = this.collection.getItem(item.parentKey);
230
- return getFirstItem(getChildNodes(parent, this.collection)).key;
269
+ if (!parent) {
270
+ return null;
271
+ }
272
+ return getFirstItem(getChildNodes(parent, this.collection))?.key ?? null;
231
273
  }
232
274
  }
233
275
 
234
276
  // Find the first row
235
- key = this.findNextKey(null, item => item.type === 'item');
277
+ key = this.findNextKey(undefined, item => item.type === 'item');
236
278
 
237
279
  // If global flag is set (or if focus mode is cell), focus the first cell in the first row.
238
- if ((key != null && item && this.isCell(item) && global) || this.focusMode === 'cell') {
280
+ if (key != null && ((item && this.isCell(item) && global) || this.focusMode === 'cell')) {
239
281
  let item = this.collection.getItem(key);
240
- key = getFirstItem(getChildNodes(item, this.collection)).key;
282
+ if (!item) {
283
+ return null;
284
+ }
285
+ key = getFirstItem(getChildNodes(item, this.collection))?.key ?? null;
241
286
  }
242
287
 
243
288
  // Otherwise, focus the row itself.
244
289
  return key;
245
290
  }
246
291
 
247
- getLastKey(key?: Key, global?: boolean) {
248
- let item: Node<T>;
292
+ getLastKey(fromKey?: Key, global?: boolean) {
293
+ let key: Key | null = fromKey ?? null;
294
+ let item: Node<T> | undefined | null;
249
295
  if (key != null) {
250
296
  item = this.collection.getItem(key);
251
297
  if (!item) {
252
- return;
298
+ return null;
253
299
  }
254
300
 
255
301
  // If global flag is not set, and a cell is currently focused,
256
302
  // move focus to the last cell in the parent row.
257
- if (this.isCell(item) && !global) {
303
+ if (this.isCell(item) && !global && item.parentKey != null) {
258
304
  let parent = this.collection.getItem(item.parentKey);
305
+ if (!parent) {
306
+ return null;
307
+ }
259
308
  let children = getChildNodes(parent, this.collection);
260
- return getLastItem(children).key;
309
+ return getLastItem(children)?.key ?? null;
261
310
  }
262
311
  }
263
312
 
264
313
  // Find the last row
265
- key = this.findPreviousKey(null, item => item.type === 'item');
314
+ key = this.findPreviousKey(undefined, item => item.type === 'item');
266
315
 
267
316
  // If global flag is set (or if focus mode is cell), focus the last cell in the last row.
268
- if ((key != null && item && this.isCell(item) && global) || this.focusMode === 'cell') {
317
+ if (key != null && ((item && this.isCell(item) && global) || this.focusMode === 'cell')) {
269
318
  let item = this.collection.getItem(key);
319
+ if (!item) {
320
+ return null;
321
+ }
270
322
  let children = getChildNodes(item, this.collection);
271
- key = getLastItem(children).key;
323
+ key = getLastItem(children)?.key ?? null;
272
324
  }
273
325
 
274
326
  // Otherwise, focus the row itself.
275
327
  return key;
276
328
  }
277
329
 
278
- getKeyPageAbove(key: Key) {
330
+ getKeyPageAbove(fromKey: Key) {
331
+ let key: Key | null = fromKey;
279
332
  let itemRect = this.layoutDelegate.getItemRect(key);
280
333
  if (!itemRect) {
281
334
  return null;
@@ -283,15 +336,19 @@ export class GridKeyboardDelegate<T, C extends GridCollection<T>> implements Key
283
336
 
284
337
  let pageY = Math.max(0, itemRect.y + itemRect.height - this.layoutDelegate.getVisibleRect().height);
285
338
 
286
- while (itemRect && itemRect.y > pageY) {
287
- key = this.getKeyAbove(key);
339
+ while (itemRect && itemRect.y > pageY && key != null) {
340
+ key = this.getKeyAbove(key) ?? null;
341
+ if (key == null) {
342
+ break;
343
+ }
288
344
  itemRect = this.layoutDelegate.getItemRect(key);
289
345
  }
290
346
 
291
347
  return key;
292
348
  }
293
349
 
294
- getKeyPageBelow(key: Key) {
350
+ getKeyPageBelow(fromKey: Key) {
351
+ let key: Key | null = fromKey;
295
352
  let itemRect = this.layoutDelegate.getItemRect(key);
296
353
 
297
354
  if (!itemRect) {
@@ -316,29 +373,39 @@ export class GridKeyboardDelegate<T, C extends GridCollection<T>> implements Key
316
373
  }
317
374
 
318
375
  getKeyForSearch(search: string, fromKey?: Key) {
376
+ let key: Key | null = fromKey ?? null;
319
377
  if (!this.collator) {
320
378
  return null;
321
379
  }
322
380
 
323
381
  let collection = this.collection;
324
- let key = fromKey ?? this.getFirstKey();
382
+ key = fromKey ?? this.getFirstKey();
383
+ if (key == null) {
384
+ return null;
385
+ }
325
386
 
326
387
  // If the starting key is a cell, search from its parent row.
327
388
  let startItem = collection.getItem(key);
389
+ if (!startItem) {
390
+ return null;
391
+ }
328
392
  if (startItem.type === 'cell') {
329
- key = startItem.parentKey;
393
+ key = startItem.parentKey ?? null;
330
394
  }
331
395
 
332
396
  let hasWrapped = false;
333
397
  while (key != null) {
334
398
  let item = collection.getItem(key);
399
+ if (!item) {
400
+ return null;
401
+ }
335
402
 
336
403
  // check row text value for match
337
404
  if (item.textValue) {
338
405
  let substring = item.textValue.slice(0, search.length);
339
406
  if (this.collator.compare(substring, search) === 0) {
340
407
  if (this.isRow(item) && this.focusMode === 'cell') {
341
- return getFirstItem(getChildNodes(item, this.collection)).key;
408
+ return getFirstItem(getChildNodes(item, this.collection))?.key ?? null;
342
409
  }
343
410
 
344
411
  return item.key;
package/src/useGrid.ts CHANGED
@@ -149,7 +149,7 @@ export function useGrid<T>(props: GridProps, state: GridState<T, GridCollection<
149
149
  },
150
150
  state.isKeyboardNavigationDisabled ? navDisabledHandlers : collectionProps,
151
151
  // If collection is empty, make sure the grid is tabbable unless there is a child tabbable element.
152
- state.collection.size === 0 && {tabIndex: hasTabbableChild ? -1 : 0},
152
+ (state.collection.size === 0 && {tabIndex: hasTabbableChild ? -1 : 0}) || undefined,
153
153
  descriptionProps
154
154
  );
155
155
 
@@ -10,7 +10,7 @@
10
10
  * governing permissions and limitations under the License.
11
11
  */
12
12
 
13
- import {DOMAttributes, FocusableElement, RefObject} from '@react-types/shared';
13
+ import {DOMAttributes, FocusableElement, Key, RefObject} from '@react-types/shared';
14
14
  import {focusSafely, getFocusableTreeWalker} from '@react-aria/focus';
15
15
  import {getScrollParent, mergeProps, scrollIntoViewport} from '@react-aria/utils';
16
16
  import {GridCollection, GridNode} from '@react-types/grid';
@@ -60,36 +60,38 @@ export function useGridCell<T, C extends GridCollection<T>>(props: GridCellProps
60
60
  } = props;
61
61
 
62
62
  let {direction} = useLocale();
63
- let {keyboardDelegate, actions: {onCellAction}} = gridMap.get(state);
63
+ let {keyboardDelegate, actions: {onCellAction}} = gridMap.get(state)!;
64
64
 
65
65
  // We need to track the key of the item at the time it was last focused so that we force
66
66
  // focus to go to the item when the DOM node is reused for a different item in a virtualizer.
67
- let keyWhenFocused = useRef(null);
67
+ let keyWhenFocused = useRef<Key | null>(null);
68
68
 
69
69
  // Handles focusing the cell. If there is a focusable child,
70
70
  // it is focused, otherwise the cell itself is focused.
71
71
  let focus = () => {
72
- let treeWalker = getFocusableTreeWalker(ref.current);
73
- if (focusMode === 'child') {
74
- // If focus is already on a focusable child within the cell, early return so we don't shift focus
75
- if (ref.current.contains(document.activeElement) && ref.current !== document.activeElement) {
76
- return;
77
- }
72
+ if (ref.current) {
73
+ let treeWalker = getFocusableTreeWalker(ref.current);
74
+ if (focusMode === 'child') {
75
+ // If focus is already on a focusable child within the cell, early return so we don't shift focus
76
+ if (ref.current.contains(document.activeElement) && ref.current !== document.activeElement) {
77
+ return;
78
+ }
78
79
 
79
- let focusable = state.selectionManager.childFocusStrategy === 'last'
80
- ? last(treeWalker)
81
- : treeWalker.firstChild() as FocusableElement;
82
- if (focusable) {
83
- focusSafely(focusable);
84
- return;
80
+ let focusable = state.selectionManager.childFocusStrategy === 'last'
81
+ ? last(treeWalker)
82
+ : treeWalker.firstChild() as FocusableElement;
83
+ if (focusable) {
84
+ focusSafely(focusable);
85
+ return;
86
+ }
85
87
  }
86
- }
87
88
 
88
- if (
89
- (keyWhenFocused.current != null && node.key !== keyWhenFocused.current) ||
90
- !ref.current.contains(document.activeElement)
91
- ) {
92
- focusSafely(ref.current);
89
+ if (
90
+ (keyWhenFocused.current != null && node.key !== keyWhenFocused.current) ||
91
+ !ref.current.contains(document.activeElement)
92
+ ) {
93
+ focusSafely(ref.current);
94
+ }
93
95
  }
94
96
  };
95
97
 
@@ -105,7 +107,7 @@ export function useGridCell<T, C extends GridCollection<T>>(props: GridCellProps
105
107
  });
106
108
 
107
109
  let onKeyDownCapture = (e: ReactKeyboardEvent) => {
108
- if (!e.currentTarget.contains(e.target as Element) || state.isKeyboardNavigationDisabled) {
110
+ if (!e.currentTarget.contains(e.target as Element) || state.isKeyboardNavigationDisabled || !ref.current || !document.activeElement) {
109
111
  return;
110
112
  }
111
113
 
@@ -115,7 +117,7 @@ export function useGridCell<T, C extends GridCollection<T>>(props: GridCellProps
115
117
  switch (e.key) {
116
118
  case 'ArrowLeft': {
117
119
  // Find the next focusable element within the cell.
118
- let focusable = direction === 'rtl'
120
+ let focusable: FocusableElement | null = direction === 'rtl'
119
121
  ? walker.nextNode() as FocusableElement
120
122
  : walker.previousNode() as FocusableElement;
121
123
 
@@ -135,12 +137,12 @@ export function useGridCell<T, C extends GridCollection<T>>(props: GridCellProps
135
137
  // of this one, only one column, and the grid doesn't focus rows, then the next key will be the
136
138
  // same as this one. In that case we need to handle focusing either the cell or the first/last
137
139
  // child, depending on the focus mode.
138
- let prev = keyboardDelegate.getKeyLeftOf(node.key);
140
+ let prev = keyboardDelegate.getKeyLeftOf?.(node.key);
139
141
  if (prev !== node.key) {
140
142
  // We prevent the capturing event from reaching children of the cell, e.g. pickers.
141
143
  // We want arrow keys to navigate to the next cell instead. We need to re-dispatch
142
144
  // the event from a higher parent so it still bubbles and gets handled by useSelectableCollection.
143
- ref.current.parentElement.dispatchEvent(
145
+ ref.current.parentElement?.dispatchEvent(
144
146
  new KeyboardEvent(e.nativeEvent.type, e.nativeEvent)
145
147
  );
146
148
  break;
@@ -163,7 +165,7 @@ export function useGridCell<T, C extends GridCollection<T>>(props: GridCellProps
163
165
  break;
164
166
  }
165
167
  case 'ArrowRight': {
166
- let focusable = direction === 'rtl'
168
+ let focusable: FocusableElement | null = direction === 'rtl'
167
169
  ? walker.previousNode() as FocusableElement
168
170
  : walker.nextNode() as FocusableElement;
169
171
 
@@ -177,12 +179,12 @@ export function useGridCell<T, C extends GridCollection<T>>(props: GridCellProps
177
179
  focusSafely(focusable);
178
180
  scrollIntoViewport(focusable, {containingElement: getScrollParent(ref.current)});
179
181
  } else {
180
- let next = keyboardDelegate.getKeyRightOf(node.key);
182
+ let next = keyboardDelegate.getKeyRightOf?.(node.key);
181
183
  if (next !== node.key) {
182
184
  // We prevent the capturing event from reaching children of the cell, e.g. pickers.
183
185
  // We want arrow keys to navigate to the next cell instead. We need to re-dispatch
184
186
  // the event from a higher parent so it still bubbles and gets handled by useSelectableCollection.
185
- ref.current.parentElement.dispatchEvent(
187
+ ref.current.parentElement?.dispatchEvent(
186
188
  new KeyboardEvent(e.nativeEvent.type, e.nativeEvent)
187
189
  );
188
190
  break;
@@ -212,7 +214,7 @@ export function useGridCell<T, C extends GridCollection<T>>(props: GridCellProps
212
214
  if (!e.altKey && ref.current.contains(e.target as Element)) {
213
215
  e.stopPropagation();
214
216
  e.preventDefault();
215
- ref.current.parentElement.dispatchEvent(
217
+ ref.current.parentElement?.dispatchEvent(
216
218
  new KeyboardEvent(e.nativeEvent.type, e.nativeEvent)
217
219
  );
218
220
  }
@@ -266,7 +268,9 @@ export function useGridCell<T, C extends GridCollection<T>>(props: GridCellProps
266
268
  let tabindex = el.getAttribute('tabindex');
267
269
  el.removeAttribute('tabindex');
268
270
  requestAnimationFrame(() => {
269
- el.setAttribute('tabindex', tabindex);
271
+ if (tabindex != null) {
272
+ el.setAttribute('tabindex', tabindex);
273
+ }
270
274
  });
271
275
  };
272
276
  }
@@ -278,10 +282,10 @@ export function useGridCell<T, C extends GridCollection<T>>(props: GridCellProps
278
282
  }
279
283
 
280
284
  function last(walker: TreeWalker) {
281
- let next: FocusableElement;
282
- let last: FocusableElement;
285
+ let next: FocusableElement | null = null;
286
+ let last: FocusableElement | null = null;
283
287
  do {
284
- last = walker.lastChild() as FocusableElement;
288
+ last = walker.lastChild() as FocusableElement | null;
285
289
  if (last) {
286
290
  next = last;
287
291
  }
package/src/useGridRow.ts CHANGED
@@ -52,8 +52,8 @@ export function useGridRow<T, C extends GridCollection<T>, S extends GridState<T
52
52
  onAction
53
53
  } = props;
54
54
 
55
- let {actions} = gridMap.get(state);
56
- let onRowAction = actions.onRowAction ? () => actions.onRowAction(node.key) : onAction;
55
+ let {actions} = gridMap.get(state)!;
56
+ let onRowAction = actions.onRowAction ? () => actions.onRowAction?.(node.key) : onAction;
57
57
  let {itemProps, ...states} = useSelectableItem({
58
58
  selectionManager: state.selectionManager,
59
59
  key: node.key,
@@ -58,7 +58,7 @@ export function useGridSelectionAnnouncement<T>(props: GridSelectionAnnouncement
58
58
 
59
59
  // If adding or removing a single row from the selection, announce the name of that item.
60
60
  let isReplace = state.selectionManager.selectionBehavior === 'replace';
61
- let messages = [];
61
+ let messages: string[] = [];
62
62
 
63
63
  if ((state.selectionManager.selectedKeys.size === 1 && isReplace)) {
64
64
  if (state.collection.getItem(state.selectionManager.selectedKeys.keys().next().value)) {
@@ -39,7 +39,7 @@ export function useHighlightSelectionDescription(props: HighlightSelectionDescri
39
39
  let selectionMode = props.selectionManager.selectionMode;
40
40
  let selectionBehavior = props.selectionManager.selectionBehavior;
41
41
 
42
- let message = undefined;
42
+ let message: string | undefined;
43
43
  if (shouldLongPress) {
44
44
  message = stringFormatter.format('longPressToSelect');
45
45
  }
package/src/utils.ts CHANGED
@@ -17,8 +17,8 @@ import type {Key, KeyboardDelegate} from '@react-types/shared';
17
17
  interface GridMapShared {
18
18
  keyboardDelegate: KeyboardDelegate,
19
19
  actions: {
20
- onRowAction: (key: Key) => void,
21
- onCellAction: (key: Key) => void
20
+ onRowAction?: (key: Key) => void,
21
+ onCellAction?: (key: Key) => void
22
22
  }
23
23
  }
24
24