@react-spectrum/card 3.0.0-alpha.5 → 3.0.0-alpha.51

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 (240) hide show
  1. package/dist/BaseLayout.main.js +213 -0
  2. package/dist/BaseLayout.main.js.map +1 -0
  3. package/dist/BaseLayout.mjs +208 -0
  4. package/dist/BaseLayout.module.js +208 -0
  5. package/dist/BaseLayout.module.js.map +1 -0
  6. package/dist/Card.main.js +52 -0
  7. package/dist/Card.main.js.map +1 -0
  8. package/dist/Card.mjs +43 -0
  9. package/dist/Card.module.js +43 -0
  10. package/dist/Card.module.js.map +1 -0
  11. package/dist/CardBase.main.js +205 -0
  12. package/dist/CardBase.main.js.map +1 -0
  13. package/dist/CardBase.mjs +200 -0
  14. package/dist/CardBase.module.js +200 -0
  15. package/dist/CardBase.module.js.map +1 -0
  16. package/dist/CardView.main.js +238 -0
  17. package/dist/CardView.main.js.map +1 -0
  18. package/dist/CardView.mjs +233 -0
  19. package/dist/CardView.module.js +233 -0
  20. package/dist/CardView.module.js.map +1 -0
  21. package/dist/CardViewContext.main.js +32 -0
  22. package/dist/CardViewContext.main.js.map +1 -0
  23. package/dist/CardViewContext.mjs +22 -0
  24. package/dist/CardViewContext.module.js +22 -0
  25. package/dist/CardViewContext.module.js.map +1 -0
  26. package/dist/GalleryLayout.main.js +230 -0
  27. package/dist/GalleryLayout.main.js.map +1 -0
  28. package/dist/GalleryLayout.mjs +225 -0
  29. package/dist/GalleryLayout.module.js +225 -0
  30. package/dist/GalleryLayout.module.js.map +1 -0
  31. package/dist/GridLayout.main.js +175 -0
  32. package/dist/GridLayout.main.js.map +1 -0
  33. package/dist/GridLayout.mjs +170 -0
  34. package/dist/GridLayout.module.js +170 -0
  35. package/dist/GridLayout.module.js.map +1 -0
  36. package/dist/WaterfallLayout.main.js +182 -0
  37. package/dist/WaterfallLayout.main.js.map +1 -0
  38. package/dist/WaterfallLayout.mjs +177 -0
  39. package/dist/WaterfallLayout.module.js +177 -0
  40. package/dist/WaterfallLayout.module.js.map +1 -0
  41. package/dist/ar-AE.main.js +7 -0
  42. package/dist/ar-AE.main.js.map +1 -0
  43. package/dist/ar-AE.mjs +9 -0
  44. package/dist/ar-AE.module.js +9 -0
  45. package/dist/ar-AE.module.js.map +1 -0
  46. package/dist/bg-BG.main.js +7 -0
  47. package/dist/bg-BG.main.js.map +1 -0
  48. package/dist/bg-BG.mjs +9 -0
  49. package/dist/bg-BG.module.js +9 -0
  50. package/dist/bg-BG.module.js.map +1 -0
  51. package/dist/card.4d5d6544.css +1671 -0
  52. package/dist/card.4d5d6544.css.map +1 -0
  53. package/dist/card_vars_css.main.js +116 -0
  54. package/dist/card_vars_css.main.js.map +1 -0
  55. package/dist/card_vars_css.mjs +118 -0
  56. package/dist/card_vars_css.module.js +118 -0
  57. package/dist/card_vars_css.module.js.map +1 -0
  58. package/dist/cs-CZ.main.js +7 -0
  59. package/dist/cs-CZ.main.js.map +1 -0
  60. package/dist/cs-CZ.mjs +9 -0
  61. package/dist/cs-CZ.module.js +9 -0
  62. package/dist/cs-CZ.module.js.map +1 -0
  63. package/dist/da-DK.main.js +7 -0
  64. package/dist/da-DK.main.js.map +1 -0
  65. package/dist/da-DK.mjs +9 -0
  66. package/dist/da-DK.module.js +9 -0
  67. package/dist/da-DK.module.js.map +1 -0
  68. package/dist/de-DE.main.js +7 -0
  69. package/dist/de-DE.main.js.map +1 -0
  70. package/dist/de-DE.mjs +9 -0
  71. package/dist/de-DE.module.js +9 -0
  72. package/dist/de-DE.module.js.map +1 -0
  73. package/dist/el-GR.main.js +7 -0
  74. package/dist/el-GR.main.js.map +1 -0
  75. package/dist/el-GR.mjs +9 -0
  76. package/dist/el-GR.module.js +9 -0
  77. package/dist/el-GR.module.js.map +1 -0
  78. package/dist/en-US.main.js +7 -0
  79. package/dist/en-US.main.js.map +1 -0
  80. package/dist/en-US.mjs +9 -0
  81. package/dist/en-US.module.js +9 -0
  82. package/dist/en-US.module.js.map +1 -0
  83. package/dist/es-ES.main.js +7 -0
  84. package/dist/es-ES.main.js.map +1 -0
  85. package/dist/es-ES.mjs +9 -0
  86. package/dist/es-ES.module.js +9 -0
  87. package/dist/es-ES.module.js.map +1 -0
  88. package/dist/et-EE.main.js +7 -0
  89. package/dist/et-EE.main.js.map +1 -0
  90. package/dist/et-EE.mjs +9 -0
  91. package/dist/et-EE.module.js +9 -0
  92. package/dist/et-EE.module.js.map +1 -0
  93. package/dist/fi-FI.main.js +7 -0
  94. package/dist/fi-FI.main.js.map +1 -0
  95. package/dist/fi-FI.mjs +9 -0
  96. package/dist/fi-FI.module.js +9 -0
  97. package/dist/fi-FI.module.js.map +1 -0
  98. package/dist/fr-FR.main.js +7 -0
  99. package/dist/fr-FR.main.js.map +1 -0
  100. package/dist/fr-FR.mjs +9 -0
  101. package/dist/fr-FR.module.js +9 -0
  102. package/dist/fr-FR.module.js.map +1 -0
  103. package/dist/he-IL.main.js +7 -0
  104. package/dist/he-IL.main.js.map +1 -0
  105. package/dist/he-IL.mjs +9 -0
  106. package/dist/he-IL.module.js +9 -0
  107. package/dist/he-IL.module.js.map +1 -0
  108. package/dist/hr-HR.main.js +7 -0
  109. package/dist/hr-HR.main.js.map +1 -0
  110. package/dist/hr-HR.mjs +9 -0
  111. package/dist/hr-HR.module.js +9 -0
  112. package/dist/hr-HR.module.js.map +1 -0
  113. package/dist/hu-HU.main.js +7 -0
  114. package/dist/hu-HU.main.js.map +1 -0
  115. package/dist/hu-HU.mjs +9 -0
  116. package/dist/hu-HU.module.js +9 -0
  117. package/dist/hu-HU.module.js.map +1 -0
  118. package/dist/import.mjs +26 -0
  119. package/dist/intlStrings.main.js +108 -0
  120. package/dist/intlStrings.main.js.map +1 -0
  121. package/dist/intlStrings.mjs +110 -0
  122. package/dist/intlStrings.module.js +110 -0
  123. package/dist/intlStrings.module.js.map +1 -0
  124. package/dist/it-IT.main.js +7 -0
  125. package/dist/it-IT.main.js.map +1 -0
  126. package/dist/it-IT.mjs +9 -0
  127. package/dist/it-IT.module.js +9 -0
  128. package/dist/it-IT.module.js.map +1 -0
  129. package/dist/ja-JP.main.js +7 -0
  130. package/dist/ja-JP.main.js.map +1 -0
  131. package/dist/ja-JP.mjs +9 -0
  132. package/dist/ja-JP.module.js +9 -0
  133. package/dist/ja-JP.module.js.map +1 -0
  134. package/dist/ko-KR.main.js +7 -0
  135. package/dist/ko-KR.main.js.map +1 -0
  136. package/dist/ko-KR.mjs +9 -0
  137. package/dist/ko-KR.module.js +9 -0
  138. package/dist/ko-KR.module.js.map +1 -0
  139. package/dist/lt-LT.main.js +7 -0
  140. package/dist/lt-LT.main.js.map +1 -0
  141. package/dist/lt-LT.mjs +9 -0
  142. package/dist/lt-LT.module.js +9 -0
  143. package/dist/lt-LT.module.js.map +1 -0
  144. package/dist/lv-LV.main.js +7 -0
  145. package/dist/lv-LV.main.js.map +1 -0
  146. package/dist/lv-LV.mjs +9 -0
  147. package/dist/lv-LV.module.js +9 -0
  148. package/dist/lv-LV.module.js.map +1 -0
  149. package/dist/main.js +21 -1447
  150. package/dist/main.js.map +1 -1
  151. package/dist/module.js +17 -1432
  152. package/dist/module.js.map +1 -1
  153. package/dist/nb-NO.main.js +7 -0
  154. package/dist/nb-NO.main.js.map +1 -0
  155. package/dist/nb-NO.mjs +9 -0
  156. package/dist/nb-NO.module.js +9 -0
  157. package/dist/nb-NO.module.js.map +1 -0
  158. package/dist/nl-NL.main.js +7 -0
  159. package/dist/nl-NL.main.js.map +1 -0
  160. package/dist/nl-NL.mjs +9 -0
  161. package/dist/nl-NL.module.js +9 -0
  162. package/dist/nl-NL.module.js.map +1 -0
  163. package/dist/pl-PL.main.js +7 -0
  164. package/dist/pl-PL.main.js.map +1 -0
  165. package/dist/pl-PL.mjs +9 -0
  166. package/dist/pl-PL.module.js +9 -0
  167. package/dist/pl-PL.module.js.map +1 -0
  168. package/dist/pt-BR.main.js +7 -0
  169. package/dist/pt-BR.main.js.map +1 -0
  170. package/dist/pt-BR.mjs +9 -0
  171. package/dist/pt-BR.module.js +9 -0
  172. package/dist/pt-BR.module.js.map +1 -0
  173. package/dist/pt-PT.main.js +7 -0
  174. package/dist/pt-PT.main.js.map +1 -0
  175. package/dist/pt-PT.mjs +9 -0
  176. package/dist/pt-PT.module.js +9 -0
  177. package/dist/pt-PT.module.js.map +1 -0
  178. package/dist/ro-RO.main.js +7 -0
  179. package/dist/ro-RO.main.js.map +1 -0
  180. package/dist/ro-RO.mjs +9 -0
  181. package/dist/ro-RO.module.js +9 -0
  182. package/dist/ro-RO.module.js.map +1 -0
  183. package/dist/ru-RU.main.js +7 -0
  184. package/dist/ru-RU.main.js.map +1 -0
  185. package/dist/ru-RU.mjs +9 -0
  186. package/dist/ru-RU.module.js +9 -0
  187. package/dist/ru-RU.module.js.map +1 -0
  188. package/dist/sk-SK.main.js +7 -0
  189. package/dist/sk-SK.main.js.map +1 -0
  190. package/dist/sk-SK.mjs +9 -0
  191. package/dist/sk-SK.module.js +9 -0
  192. package/dist/sk-SK.module.js.map +1 -0
  193. package/dist/sl-SI.main.js +7 -0
  194. package/dist/sl-SI.main.js.map +1 -0
  195. package/dist/sl-SI.mjs +9 -0
  196. package/dist/sl-SI.module.js +9 -0
  197. package/dist/sl-SI.module.js.map +1 -0
  198. package/dist/sr-SP.main.js +7 -0
  199. package/dist/sr-SP.main.js.map +1 -0
  200. package/dist/sr-SP.mjs +9 -0
  201. package/dist/sr-SP.module.js +9 -0
  202. package/dist/sr-SP.module.js.map +1 -0
  203. package/dist/sv-SE.main.js +7 -0
  204. package/dist/sv-SE.main.js.map +1 -0
  205. package/dist/sv-SE.mjs +9 -0
  206. package/dist/sv-SE.module.js +9 -0
  207. package/dist/sv-SE.module.js.map +1 -0
  208. package/dist/tr-TR.main.js +7 -0
  209. package/dist/tr-TR.main.js.map +1 -0
  210. package/dist/tr-TR.mjs +9 -0
  211. package/dist/tr-TR.module.js +9 -0
  212. package/dist/tr-TR.module.js.map +1 -0
  213. package/dist/types.d.ts +43 -41
  214. package/dist/types.d.ts.map +1 -1
  215. package/dist/uk-UA.main.js +7 -0
  216. package/dist/uk-UA.main.js.map +1 -0
  217. package/dist/uk-UA.mjs +9 -0
  218. package/dist/uk-UA.module.js +9 -0
  219. package/dist/uk-UA.module.js.map +1 -0
  220. package/dist/zh-CN.main.js +7 -0
  221. package/dist/zh-CN.main.js.map +1 -0
  222. package/dist/zh-CN.mjs +9 -0
  223. package/dist/zh-CN.module.js +9 -0
  224. package/dist/zh-CN.module.js.map +1 -0
  225. package/dist/zh-TW.main.js +7 -0
  226. package/dist/zh-TW.main.js.map +1 -0
  227. package/dist/zh-TW.mjs +9 -0
  228. package/dist/zh-TW.module.js +9 -0
  229. package/dist/zh-TW.module.js.map +1 -0
  230. package/package.json +30 -23
  231. package/src/BaseLayout.tsx +49 -45
  232. package/src/Card.tsx +1 -0
  233. package/src/CardBase.tsx +12 -14
  234. package/src/CardView.tsx +71 -51
  235. package/src/CardViewContext.tsx +10 -2
  236. package/src/GalleryLayout.tsx +7 -5
  237. package/src/GridLayout.tsx +12 -44
  238. package/src/WaterfallLayout.tsx +15 -12
  239. package/src/index.ts +10 -5
  240. package/dist/main.css +0 -1
@@ -1,3 +1,4 @@
1
+ // @ts-nocheck
1
2
  /*
2
3
  * Copyright 2021 Adobe. All rights reserved.
3
4
  * This file is licensed to you under the Apache License, Version 2.0 (the "License");
@@ -10,10 +11,10 @@
10
11
  * governing permissions and limitations under the License.
11
12
  */
12
13
 
13
- import {Direction, KeyboardDelegate, Node} from '@react-types/shared';
14
+ import {Direction, Key, KeyboardDelegate, Node} from '@react-types/shared';
15
+ import {getChildNodes, getFirstItem} from '@react-stately/collections';
14
16
  import {GridCollection} from '@react-stately/grid';
15
17
  import {InvalidationContext, Layout, LayoutInfo, Rect, Size} from '@react-stately/virtualizer';
16
- import {Key} from 'react';
17
18
  import {Scale} from '@react-types/provider';
18
19
 
19
20
  export interface BaseLayoutOptions {
@@ -27,7 +28,12 @@ export interface BaseLayoutOptions {
27
28
  margin?: number
28
29
  }
29
30
 
30
- export class BaseLayout<T> extends Layout<Node<T>> implements KeyboardDelegate {
31
+ interface CardViewLayoutOptions {
32
+ isLoading: boolean,
33
+ direction: Direction
34
+ }
35
+
36
+ export class BaseLayout<T> extends Layout<Node<T>, CardViewLayoutOptions> implements KeyboardDelegate {
31
37
  protected contentSize: Size;
32
38
  protected layoutInfos: Map<Key, LayoutInfo>;
33
39
  protected collator: Intl.Collator;
@@ -48,8 +54,10 @@ export class BaseLayout<T> extends Layout<Node<T>> implements KeyboardDelegate {
48
54
  this.margin = options.margin || 24;
49
55
  }
50
56
 
51
- validate(invalidationContext: InvalidationContext<Node<T>, unknown>) {
57
+ update(invalidationContext: InvalidationContext<CardViewLayoutOptions>): void {
52
58
  this.collection = this.virtualizer.collection as GridCollection<T>;
59
+ this.isLoading = invalidationContext.layoutOptions?.isLoading || false;
60
+ this.direction = invalidationContext.layoutOptions?.direction || 'ltr';
53
61
  this.buildCollection(invalidationContext);
54
62
 
55
63
  // Remove layout info that doesn't exist in new collection
@@ -73,21 +81,21 @@ export class BaseLayout<T> extends Layout<Node<T>> implements KeyboardDelegate {
73
81
  }
74
82
 
75
83
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
76
- buildCollection(invalidationContext?: InvalidationContext<Node<T>, unknown>) {}
84
+ buildCollection(invalidationContext?: InvalidationContext): void {}
77
85
 
78
- getContentSize() {
86
+ getContentSize(): number {
79
87
  return this.contentSize;
80
88
  }
81
89
 
82
- getLayoutInfo(key: Key) {
83
- return this.layoutInfos.get(key);
90
+ getLayoutInfo(key: Key): LayoutInfo {
91
+ return this.layoutInfos.get(key)!;
84
92
  }
85
93
 
86
- getVisibleLayoutInfos(rect) {
94
+ getVisibleLayoutInfos(rect: Rect, excludePersistedKeys = false): LayoutInfo[] {
87
95
  let res: LayoutInfo[] = [];
88
96
 
89
97
  for (let layoutInfo of this.layoutInfos.values()) {
90
- if (this.isVisible(layoutInfo, rect)) {
98
+ if (this.isVisible(layoutInfo, rect, excludePersistedKeys)) {
91
99
  res.push(layoutInfo);
92
100
  }
93
101
  }
@@ -95,24 +103,20 @@ export class BaseLayout<T> extends Layout<Node<T>> implements KeyboardDelegate {
95
103
  return res;
96
104
  }
97
105
 
98
- isVisible(layoutInfo: LayoutInfo, rect: Rect) {
99
- return layoutInfo.rect.intersects(rect);
100
- }
106
+ isVisible(layoutInfo: LayoutInfo, rect: Rect, excludePersistedKeys: boolean): boolean {
107
+ if (layoutInfo.rect.intersects(rect)) {
108
+ return true;
109
+ }
101
110
 
102
- getInitialLayoutInfo(layoutInfo: LayoutInfo) {
103
- layoutInfo.opacity = 0;
104
- layoutInfo.transform = 'scale3d(0.8, 0.8, 0.8)';
105
- return layoutInfo;
106
- }
111
+ if (!excludePersistedKeys) {
112
+ return this.virtualizer.isPersistedKey(layoutInfo.key);
113
+ }
107
114
 
108
- getFinalLayoutInfo(layoutInfo: LayoutInfo) {
109
- layoutInfo.opacity = 0;
110
- layoutInfo.transform = 'scale3d(0.8, 0.8, 0.8)';
111
- return layoutInfo;
115
+ return false;
112
116
  }
113
117
 
114
- _findClosestLayoutInfo(target: Rect, rect: Rect) {
115
- let layoutInfos = this.getVisibleLayoutInfos(rect);
118
+ _findClosestLayoutInfo(target: Rect, rect: Rect): LayoutInfo | null {
119
+ let layoutInfos = this.getVisibleLayoutInfos(rect, true);
116
120
  let best = null;
117
121
  let bestDistance = Infinity;
118
122
 
@@ -135,30 +139,30 @@ export class BaseLayout<T> extends Layout<Node<T>> implements KeyboardDelegate {
135
139
  return best;
136
140
  }
137
141
 
138
- _findClosest(target: Rect, rect: Rect) {
142
+ _findClosest(target: Rect, rect: Rect): LayoutInfo | null {
139
143
  let best = this._findClosestLayoutInfo(target, rect);
140
144
  return best || null;
141
145
  }
142
146
 
143
- getKeyBelow(key: Key) {
147
+ getKeyBelow(key: Key): Node<T> | undefined {
144
148
  // Expected key is the currently focused cell so we need the parent row key
145
149
  let parentRowKey = this.collection.getItem(key).parentKey;
146
150
  let layoutInfo = this.getLayoutInfo(parentRowKey);
147
151
  let rect = new Rect(layoutInfo.rect.x, layoutInfo.rect.maxY + 1, layoutInfo.rect.width, this.virtualizer.visibleRect.height);
148
152
  let closestRow = this.collection.getItem(this._findClosest(layoutInfo.rect, rect)?.key);
149
- return closestRow?.childNodes[0]?.key;
153
+ return getFirstItem(getChildNodes(closestRow, this.collection))?.key;
150
154
  }
151
155
 
152
- getKeyAbove(key: Key) {
156
+ getKeyAbove(key: Key): Node<T> | undefined {
153
157
  // Expected key is the currently focused cell so we need the parent row key
154
158
  let parentRowKey = this.collection.getItem(key).parentKey;
155
159
  let layoutInfo = this.getLayoutInfo(parentRowKey);
156
160
  let rect = new Rect(layoutInfo.rect.x, 0, layoutInfo.rect.width, layoutInfo.rect.y - 1);
157
161
  let closestRow = this.collection.getItem(this._findClosest(layoutInfo.rect, rect)?.key);
158
- return closestRow?.childNodes[0]?.key;
162
+ return getFirstItem(getChildNodes(closestRow, this.collection))?.key;
159
163
  }
160
164
 
161
- getKeyRightOf(key: Key) {
165
+ getKeyRightOf(key: Key): Node<T> | undefined {
162
166
  // Expected key is the currently focused cell so we need the parent row key
163
167
  let parentRowKey = this.collection.getItem(key).parentKey;
164
168
  key = this.direction === 'rtl' ? this.collection.getKeyBefore(parentRowKey) : this.collection.getKeyAfter(parentRowKey);
@@ -167,13 +171,13 @@ export class BaseLayout<T> extends Layout<Node<T>> implements KeyboardDelegate {
167
171
  let item = this.collection.getItem(key);
168
172
  // Don't check if item is disabled because we want to be able to focus disabled items in a grid (double check this)
169
173
  if (item.type === 'item') {
170
- return item.childNodes[0].key;
174
+ return getFirstItem(getChildNodes(item, this.collection))?.key;
171
175
  }
172
176
  key = this.direction === 'rtl' ? this.collection.getKeyBefore(key) : this.collection.getKeyAfter(key);
173
177
  }
174
178
  }
175
179
 
176
- getKeyLeftOf(key: Key) {
180
+ getKeyLeftOf(key: Key): Node<T> | undefined {
177
181
  // Expected key is the currently focused cell so we need the parent row key
178
182
  let parentRowKey = this.collection.getItem(key).parentKey;
179
183
  key = this.direction === 'rtl' ? this.collection.getKeyAfter(parentRowKey) : this.collection.getKeyBefore(parentRowKey);
@@ -181,26 +185,26 @@ export class BaseLayout<T> extends Layout<Node<T>> implements KeyboardDelegate {
181
185
  let item = this.collection.getItem(key);
182
186
  // Don't check if item is disabled because we want to be able to focus disabled items in a grid (double check this)
183
187
  if (item.type === 'item') {
184
- return item.childNodes[0].key;
188
+ return getFirstItem(getChildNodes(item, this.collection))?.key;
185
189
  }
186
190
 
187
191
  key = this.direction === 'rtl' ? this.collection.getKeyAfter(key) : this.collection.getKeyBefore(key);
188
192
  }
189
193
  }
190
194
 
191
- getFirstKey() {
195
+ getFirstKey(): Node<T> | undefined {
192
196
  let firstRow = this.collection.getItem(this.collection.getFirstKey());
193
- return firstRow.childNodes[0].key;
197
+ return getFirstItem(getChildNodes(firstRow, this.collection))?.key;
194
198
  }
195
199
 
196
- getLastKey() {
200
+ getLastKey(): Node<T> | undefined {
197
201
  let lastRow = this.collection.getItem(this.collection.getLastKey());
198
- return lastRow.childNodes[0].key;
202
+ return getFirstItem(getChildNodes(lastRow, this.collection))?.key;
199
203
  }
200
204
 
201
205
  // TODO: pretty unwieldy because it needs to bounce back and forth between the parent key and the child key
202
206
  // Perhaps have layoutInfo store childKey as well so we don't need to do this? Or maybe make the layoutInfos be the cells instead of the rows?
203
- getKeyPageAbove(key: Key) {
207
+ getKeyPageAbove(key: Key): Node<T> | undefined {
204
208
  // Expected key is the currently focused cell so we need the parent row key
205
209
  let parentRowKey = this.collection.getItem(key).parentKey;
206
210
  let layoutInfo = this.getLayoutInfo(parentRowKey);
@@ -214,14 +218,14 @@ export class BaseLayout<T> extends Layout<Node<T>> implements KeyboardDelegate {
214
218
 
215
219
  if (layoutInfo && layoutInfo.rect.y > pageY) {
216
220
  while (layoutInfo && layoutInfo.rect.y > pageY) {
217
- let childKey = this.collection.getItem(layoutInfo.key).childNodes[0].key;
221
+ let childKey = getFirstItem(getChildNodes(this.collection.getItem(layoutInfo.key), this.collection))?.key;
218
222
  let keyAbove = this.collection.getItem(this.getKeyAbove(childKey))?.parentKey;
219
223
  layoutInfo = this.getLayoutInfo(keyAbove);
220
224
  }
221
225
  }
222
226
 
223
227
  if (layoutInfo) {
224
- let childKey = this.collection.getItem(layoutInfo.key).childNodes[0].key;
228
+ let childKey = getFirstItem(getChildNodes(this.collection.getItem(layoutInfo.key), this.collection))?.key;
225
229
  return childKey;
226
230
  }
227
231
  }
@@ -231,7 +235,7 @@ export class BaseLayout<T> extends Layout<Node<T>> implements KeyboardDelegate {
231
235
 
232
236
  // TODO: pretty unwieldy because it needs to bounce back and forth between the parent key and the child key
233
237
  // Perhaps have layoutInfo store childKey as well so we don't need to do this?
234
- getKeyPageBelow(key: Key) {
238
+ getKeyPageBelow(key: Key): Node<T> | undefined {
235
239
  // Expected key is the currently focused cell so we need the parent row key
236
240
  let parentRowKey = this.collection.getItem(key).parentKey;
237
241
  let layoutInfo = this.getLayoutInfo(parentRowKey);
@@ -243,14 +247,14 @@ export class BaseLayout<T> extends Layout<Node<T>> implements KeyboardDelegate {
243
247
  layoutInfo = this.getLayoutInfo(keyBelow);
244
248
  if (layoutInfo && layoutInfo.rect.y < pageY) {
245
249
  while (layoutInfo && layoutInfo.rect.y < pageY) {
246
- let childKey = this.collection.getItem(layoutInfo.key).childNodes[0].key;
250
+ let childKey = getFirstItem(getChildNodes(this.collection.getItem(layoutInfo.key), this.collection))?.key;
247
251
  let keyBelow = this.collection.getItem(this.getKeyBelow(childKey))?.parentKey;
248
252
  layoutInfo = this.getLayoutInfo(keyBelow);
249
253
  }
250
254
  }
251
255
 
252
256
  if (layoutInfo) {
253
- let childKey = this.collection.getItem(layoutInfo.key).childNodes[0].key;
257
+ let childKey = getFirstItem(getChildNodes(this.collection.getItem(layoutInfo.key), this.collection))?.key;
254
258
  return childKey;
255
259
  }
256
260
  }
@@ -258,7 +262,7 @@ export class BaseLayout<T> extends Layout<Node<T>> implements KeyboardDelegate {
258
262
  return this.getLastKey();
259
263
  }
260
264
 
261
- getKeyForSearch(search: string, fromKey?: Key) {
265
+ getKeyForSearch(search: string, fromKey?: Key): Node<T> | undefined | null {
262
266
  if (!this.collator) {
263
267
  return null;
264
268
  }
@@ -274,7 +278,7 @@ export class BaseLayout<T> extends Layout<Node<T>> implements KeyboardDelegate {
274
278
  if (item.textValue) {
275
279
  let substring = item.textValue.slice(0, search.length);
276
280
  if (this.collator.compare(substring, search) === 0) {
277
- return [...item.childNodes][0].key;
281
+ return getFirstItem(getChildNodes(item, this.collection))?.key;
278
282
  }
279
283
  }
280
284
 
package/src/Card.tsx CHANGED
@@ -1,3 +1,4 @@
1
+ // @ts-nocheck
1
2
  /*
2
3
  * Copyright 2021 Adobe. All rights reserved.
3
4
  * This file is licensed to you under the Apache License, Version 2.0 (the "License");
package/src/CardBase.tsx CHANGED
@@ -1,3 +1,4 @@
1
+ // @ts-nocheck
1
2
  /*
2
3
  * Copyright 2021 Adobe. All rights reserved.
3
4
  * This file is licensed to you under the Apache License, Version 2.0 (the "License");
@@ -15,8 +16,7 @@ import {Checkbox} from '@react-spectrum/checkbox';
15
16
  import {classNames, SlotProvider, useDOMRef, useHasChild, useStyleProps} from '@react-spectrum/utils';
16
17
  import {DOMRef, Node} from '@react-types/shared';
17
18
  import {filterDOMProps, mergeProps, useLayoutEffect, useResizeObserver, useSlotId} from '@react-aria/utils';
18
- import {FocusRing} from '@react-aria/focus';
19
- import {getFocusableTreeWalker} from '@react-aria/focus';
19
+ import {FocusRing, getFocusableTreeWalker} from '@react-aria/focus';
20
20
  import React, {HTMLAttributes, useCallback, useMemo, useRef, useState} from 'react';
21
21
  import styles from '@adobe/spectrum-css-temp/components/card/vars.css';
22
22
  import {useCardViewContext} from './CardViewContext';
@@ -28,7 +28,10 @@ interface CardBaseProps<T> extends SpectrumCardProps {
28
28
  item?: Node<T>
29
29
  }
30
30
 
31
- function CardBase<T extends object>(props: CardBaseProps<T>, ref: DOMRef<HTMLDivElement>) {
31
+ /**
32
+ * TODO: Add description of component here.
33
+ */
34
+ export const CardBase = React.forwardRef(function CardBase<T extends object>(props: CardBaseProps<T>, ref: DOMRef<HTMLDivElement>) {
32
35
  props = useProviderProps(props);
33
36
  let context = useCardViewContext() || {}; // we can call again here, won't change from Card.tsx
34
37
  let {state} = context;
@@ -36,7 +39,7 @@ function CardBase<T extends object>(props: CardBaseProps<T>, ref: DOMRef<HTMLDiv
36
39
  let {
37
40
  isQuiet,
38
41
  orientation = 'vertical',
39
- articleProps = {},
42
+ articleProps = {role: 'article'},
40
43
  item,
41
44
  layout,
42
45
  children
@@ -50,7 +53,7 @@ function CardBase<T extends object>(props: CardBaseProps<T>, ref: DOMRef<HTMLDiv
50
53
  let {styleProps} = useStyleProps(props);
51
54
  let {cardProps, titleProps, contentProps} = useCard(props);
52
55
  let domRef = useDOMRef(ref);
53
- let gridRef = useRef<HTMLDivElement>();
56
+ let gridRef = useRef<HTMLDivElement>(undefined);
54
57
  let checkboxRef = useRef(null);
55
58
 
56
59
  // cards are only interactive if there is a selection manager and it allows selection
@@ -93,6 +96,7 @@ function CardBase<T extends object>(props: CardBaseProps<T>, ref: DOMRef<HTMLDiv
93
96
  heading: {UNSAFE_className: classNames(styles, 'spectrum-Card-heading'), ...titleProps},
94
97
  content: {UNSAFE_className: classNames(styles, 'spectrum-Card-content'), ...contentProps},
95
98
  detail: {UNSAFE_className: classNames(styles, 'spectrum-Card-detail')}
99
+ // eslint-disable-next-line react-hooks/exhaustive-deps
96
100
  }), [titleProps, contentProps, height, isQuiet, orientation]);
97
101
 
98
102
  useLayoutEffect(() => {
@@ -111,7 +115,7 @@ function CardBase<T extends object>(props: CardBaseProps<T>, ref: DOMRef<HTMLDiv
111
115
 
112
116
  return (
113
117
  <FocusRing focusRingClass={classNames(styles, 'focus-ring')}>
114
- <article
118
+ <div
115
119
  {...styleProps}
116
120
  {...mergeProps(cardProps, focusWithinProps, hoverProps, filterDOMProps(props), articleProps)}
117
121
  ref={domRef}
@@ -147,10 +151,10 @@ function CardBase<T extends object>(props: CardBaseProps<T>, ref: DOMRef<HTMLDiv
147
151
  </SlotProvider>
148
152
  <div className={classNames(styles, 'spectrum-Card-decoration')} />
149
153
  </div>
150
- </article>
154
+ </div>
151
155
  </FocusRing>
152
156
  );
153
- }
157
+ });
154
158
 
155
159
  interface AriaCardOptions extends AriaCardProps {
156
160
  }
@@ -182,9 +186,3 @@ function useCard(props: AriaCardOptions): CardAria {
182
186
  contentProps
183
187
  };
184
188
  }
185
-
186
- /**
187
- * TODO: Add description of component here.
188
- */
189
- const _CardBase = React.forwardRef(CardBase);
190
- export {_CardBase as CardBase};
package/src/CardView.tsx CHANGED
@@ -1,3 +1,4 @@
1
+ // @ts-nocheck
1
2
  /*
2
3
  * Copyright 2021 Adobe. All rights reserved.
3
4
  * This file is licensed to you under the Apache License, Version 2.0 (the "License");
@@ -17,18 +18,22 @@ import {DOMRef, DOMRefValue, Node} from '@react-types/shared';
17
18
  import {GridCollection, useGridState} from '@react-stately/grid';
18
19
  // @ts-ignore
19
20
  import intlMessages from '../intl/*.json';
21
+ import {mergeProps} from '@react-aria/utils';
20
22
  import {ProgressCircle} from '@react-spectrum/progress';
21
- import React, {ReactElement, useCallback, useMemo, useRef} from 'react';
23
+ import React, {ReactElement, ReactNode, useCallback, useMemo, useRef} from 'react';
22
24
  import {ReusableView} from '@react-stately/virtualizer';
23
25
  import {SpectrumCardViewProps} from '@react-types/card';
24
26
  import styles from '@adobe/spectrum-css-temp/components/card/vars.css';
25
- import {useCollator, useLocale, useMessageFormatter} from '@react-aria/i18n';
27
+ import {useCollator, useLocale, useLocalizedStringFormatter} from '@react-aria/i18n';
26
28
  import {useGrid, useGridCell, useGridRow} from '@react-aria/grid';
27
29
  import {useListState} from '@react-stately/list';
28
30
  import {useProvider} from '@react-spectrum/provider';
29
31
  import {Virtualizer, VirtualizerItem} from '@react-aria/virtualizer';
30
32
 
31
- function CardView<T extends object>(props: SpectrumCardViewProps<T>, ref: DOMRef<HTMLDivElement>) {
33
+ /**
34
+ * TODO: Add description of component here.
35
+ */
36
+ export const CardView = React.forwardRef(function CardView<T extends object>(props: SpectrumCardViewProps<T>, ref: DOMRef<HTMLDivElement>) {
32
37
  let {scale} = useProvider();
33
38
  let {styleProps} = useStyleProps(props);
34
39
  let domRef = useDOMRef(ref);
@@ -46,7 +51,6 @@ function CardView<T extends object>(props: SpectrumCardViewProps<T>, ref: DOMRef
46
51
  let cardViewLayout = useMemo(() => typeof layout === 'function' ? new layout({collator, cardOrientation, scale}) : layout, [layout, collator, cardOrientation, scale]);
47
52
  let layoutType = cardViewLayout.layoutType;
48
53
 
49
- let formatMessage = useMessageFormatter(intlMessages);
50
54
  let {direction} = useLocale();
51
55
  let {collection} = useListState(props);
52
56
 
@@ -78,8 +82,6 @@ function CardView<T extends object>(props: SpectrumCardViewProps<T>, ref: DOMRef
78
82
 
79
83
  cardViewLayout.collection = gridCollection;
80
84
  cardViewLayout.disabledKeys = state.disabledKeys;
81
- cardViewLayout.isLoading = isLoading;
82
- cardViewLayout.direction = direction;
83
85
 
84
86
  let {gridProps} = useGrid({
85
87
  ...props,
@@ -87,13 +89,16 @@ function CardView<T extends object>(props: SpectrumCardViewProps<T>, ref: DOMRef
87
89
  keyboardDelegate: cardViewLayout
88
90
  }, state, domRef);
89
91
 
90
- type View = ReusableView<Node<T>, unknown>;
91
- let renderWrapper = (parent: View, reusableView: View) => (
92
+ type View = ReusableView<Node<T>, ReactNode>;
93
+ let renderWrapper = useCallback((parent: View, reusableView: View) => (
92
94
  <VirtualizerItem
93
95
  key={reusableView.key}
94
- reusableView={reusableView}
95
- parent={parent} />
96
- );
96
+ layoutInfo={reusableView.layoutInfo}
97
+ virtualizer={reusableView.virtualizer}
98
+ parent={parent?.layoutInfo}>
99
+ {reusableView.rendered}
100
+ </VirtualizerItem>
101
+ ), []);
97
102
 
98
103
  let focusedKey = state.selectionManager.focusedKey;
99
104
  let focusedItem = gridCollection.getItem(state.selectionManager.focusedKey);
@@ -101,62 +106,69 @@ function CardView<T extends object>(props: SpectrumCardViewProps<T>, ref: DOMRef
101
106
  focusedKey = focusedItem.parentKey;
102
107
  }
103
108
 
104
- let margin = cardViewLayout.margin || 0;
105
- let virtualizer = cardViewLayout.virtualizer;
106
- let scrollToItem = useCallback((key) => {
107
- virtualizer && virtualizer.scrollToItem(key, {
108
- duration: 0,
109
- offsetY: margin
110
- });
111
- }, [margin, virtualizer]);
109
+ let persistedKeys = useMemo(() => focusedKey != null ? new Set([focusedKey]) : null, [focusedKey]);
112
110
 
113
111
  // TODO: does aria-row count and aria-col count need to be modified? Perhaps aria-col count needs to be omitted
114
112
  return (
115
- <CardViewContext.Provider value={{state, isQuiet, layout: cardViewLayout, cardOrientation}}>
113
+ <CardViewContext.Provider value={{state, isQuiet, layout: cardViewLayout, cardOrientation, renderEmptyState}}>
116
114
  <Virtualizer
117
115
  {...gridProps}
118
116
  {...styleProps}
119
117
  className={classNames(styles, 'spectrum-CardView')}
120
118
  ref={domRef}
121
- focusedKey={focusedKey}
119
+ persistedKeys={persistedKeys}
122
120
  scrollDirection="vertical"
123
121
  layout={cardViewLayout}
124
122
  collection={gridCollection}
125
123
  isLoading={isLoading}
126
124
  onLoadMore={onLoadMore}
125
+ layoutOptions={useMemo(() => ({isLoading, direction}), [isLoading, direction])}
127
126
  renderWrapper={renderWrapper}
128
- transitionDuration={isLoading ? 160 : 220}
129
- scrollToItem={scrollToItem}>
130
- {(type, item) => {
127
+ style={{
128
+ ...styleProps.style,
129
+ scrollPaddingTop: cardViewLayout.margin || 0
130
+ }}>
131
+ {useCallback((type, item) => {
131
132
  if (type === 'item') {
132
133
  return (
133
134
  <InternalCard item={item} />
134
135
  );
135
136
  } else if (type === 'loader') {
136
- return (
137
- <CenteredWrapper>
138
- <ProgressCircle
139
- isIndeterminate
140
- aria-label={state.collection.size > 0 ? formatMessage('loadingMore') : formatMessage('loading')} />
141
- </CenteredWrapper>
142
- );
137
+ return <LoadingState />;
143
138
  } else if (type === 'placeholder') {
144
- let emptyState = renderEmptyState ? renderEmptyState() : null;
145
- if (emptyState == null) {
146
- return null;
147
- }
148
-
149
- return (
150
- <CenteredWrapper>
151
- {emptyState}
152
- </CenteredWrapper>
153
- );
139
+ return <EmptyState />;
154
140
  }
155
- }}
141
+ }, [])}
156
142
  </Virtualizer>
157
143
  </CardViewContext.Provider>
158
144
 
159
145
  );
146
+ }) as <T>(props: SpectrumCardViewProps<T> & {ref?: DOMRef<HTMLDivElement>}) => ReactElement;
147
+
148
+ function LoadingState() {
149
+ let {state} = useCardViewContext();
150
+ let stringFormatter = useLocalizedStringFormatter(intlMessages, '@react-spectrum/card');
151
+ return (
152
+ <CenteredWrapper>
153
+ <ProgressCircle
154
+ isIndeterminate
155
+ aria-label={state.collection.size > 0 ? stringFormatter.format('loadingMore') : stringFormatter.format('loading')} />
156
+ </CenteredWrapper>
157
+ );
158
+ }
159
+
160
+ function EmptyState() {
161
+ let {renderEmptyState} = useCardViewContext();
162
+ let emptyState = renderEmptyState ? renderEmptyState() : null;
163
+ if (emptyState == null) {
164
+ return null;
165
+ }
166
+
167
+ return (
168
+ <CenteredWrapper>
169
+ {emptyState}
170
+ </CenteredWrapper>
171
+ );
160
172
  }
161
173
 
162
174
  function CenteredWrapper({children}) {
@@ -181,11 +193,11 @@ function InternalCard(props) {
181
193
  let {state, cardOrientation, isQuiet, layout} = useCardViewContext();
182
194
 
183
195
  let layoutType = layout.layoutType;
184
- let rowRef = useRef();
185
- let cellRef = useRef<DOMRefValue<HTMLDivElement>>();
196
+ let rowRef = useRef(undefined);
197
+ let cellRef = useRef<DOMRefValue<HTMLDivElement>>(undefined);
186
198
  let unwrappedRef = useUnwrapDOMRef(cellRef);
187
199
 
188
- let {rowProps} = useGridRow({
200
+ let {rowProps: gridRowProps} = useGridRow({
189
201
  node: item,
190
202
  isVirtualized: true
191
203
  }, state, rowRef);
@@ -195,6 +207,20 @@ function InternalCard(props) {
195
207
  focusMode: 'cell'
196
208
  }, state, unwrappedRef);
197
209
 
210
+ // Prevent space key from scrolling the CardView if triggered on a disabled item or on a Card in a selectionMode="none" CardView.
211
+ let allowsInteraction = state.selectionManager.selectionMode !== 'none';
212
+ let isDisabled = !allowsInteraction || state.disabledKeys.has(item.key);
213
+
214
+ let onKeyDown = (e) => {
215
+ if (e.key === ' ' && isDisabled) {
216
+ e.preventDefault();
217
+ }
218
+ };
219
+
220
+ let rowProps = mergeProps(
221
+ gridRowProps,
222
+ {onKeyDown}
223
+ );
198
224
 
199
225
  if (layoutType === 'grid' || layoutType === 'gallery') {
200
226
  isQuiet = true;
@@ -222,9 +248,3 @@ function InternalCard(props) {
222
248
  </div>
223
249
  );
224
250
  }
225
-
226
- /**
227
- * TODO: Add description of component here.
228
- */
229
- const _CardView = React.forwardRef(CardView) as <T>(props: SpectrumCardViewProps<T> & {ref?: DOMRef<HTMLDivElement>}) => ReactElement;
230
- export {_CardView as CardView};
@@ -1,3 +1,4 @@
1
+ // @ts-nocheck
1
2
  /*
2
3
  * Copyright 2020 Adobe. All rights reserved.
3
4
  * This file is licensed to you under the Apache License, Version 2.0 (the "License");
@@ -12,8 +13,15 @@
12
13
 
13
14
  import React, {useContext} from 'react';
14
15
 
15
- export const CardViewContext = React.createContext(null);
16
+ export interface CardViewContextValue {
17
+ state: 'idle' | 'loading' | 'error',
18
+ isQuiet: boolean,
19
+ layout: 'grid' | 'gallery' | 'waterfall',
20
+ cardOrientation: 'horizontal' | 'vertical',
21
+ renderEmptyState: () => React.ReactNode
22
+ }
23
+ export const CardViewContext = React.createContext<CardViewContextValue>(null);
16
24
 
17
- export function useCardViewContext() {
25
+ export function useCardViewContext(): CardViewContextValue | null {
18
26
  return useContext(CardViewContext);
19
27
  }
@@ -1,3 +1,4 @@
1
+ // @ts-nocheck
1
2
  /*
2
3
  * Copyright 2021 Adobe. All rights reserved.
3
4
  * This file is licensed to you under the Apache License, Version 2.0 (the "License");
@@ -86,7 +87,7 @@ export class GalleryLayout<T> extends BaseLayout<T> {
86
87
  this.margin = options.margin != null ? options.margin : DEFAULT_OPTIONS[cardSize].margin;
87
88
  }
88
89
 
89
- get layoutType() {
90
+ get layoutType(): string {
90
91
  return 'gallery';
91
92
  }
92
93
 
@@ -95,7 +96,7 @@ export class GalleryLayout<T> extends BaseLayout<T> {
95
96
  * the widest in the row until it can't give anymore, then move to the second widest and so forth.
96
97
  * Do this until all assets meet the min-width.
97
98
  * */
98
- _distributeWidths(widths) {
99
+ _distributeWidths(widths: number[]): boolean {
99
100
  // create a copy of the widths array and sort it largest to smallest
100
101
  let sortedWidths = widths.concat().sort((a, b) => a[1] > b[1] ? -1 : 1);
101
102
  for (let width of widths) {
@@ -109,6 +110,7 @@ export class GalleryLayout<T> extends BaseLayout<T> {
109
110
  if (widths[item[0]][1] > this.minItemSize.width) {
110
111
  // subtract the delta from the width, if it's still greater than the min width
111
112
  // then we have finished, subtract the delta permanently from that width
113
+ // eslint-disable-next-line max-depth
112
114
  if (widths[item[0]][1] - delta > this.minItemSize.width) {
113
115
  widths[item[0]][1] -= delta;
114
116
  delta = 0;
@@ -132,13 +134,13 @@ export class GalleryLayout<T> extends BaseLayout<T> {
132
134
  return true;
133
135
  }
134
136
 
135
- buildCollection() {
137
+ buildCollection(): void {
136
138
  let visibleWidth = this.virtualizer.visibleRect.width;
137
139
  let visibleHeight = this.virtualizer.visibleRect.height;
138
140
  let y = this.margin;
139
141
  let availableWidth = visibleWidth - this.margin * 2;
140
142
 
141
- // If avaliable width is not greater than 0, skip node layout calculations
143
+ // If available width is not greater than 0, skip node layout calculations
142
144
  if (availableWidth > 0) {
143
145
  // Compute aspect ratios for all of the items, and the total width if all items were on in a single row.
144
146
  let ratios = [];
@@ -219,7 +221,7 @@ export class GalleryLayout<T> extends BaseLayout<T> {
219
221
  if (this.isLoading) {
220
222
  let loaderY = y;
221
223
  let loaderHeight = 60;
222
- // If there aren't any items, make loader take all avaliable room and remove margin from y calculation
224
+ // If there aren't any items, make loader take all available room and remove margin from y calculation
223
225
  // so it doesn't scroll
224
226
  if (this.collection.size === 0) {
225
227
  loaderY = 0;